home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-26  |  189.6 KB  |  7,814 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * screen.c: code for displaying on the screen
  12.  *
  13.  * Output to the screen (console, terminal emulator or GUI window) is minimized
  14.  * by remembering what is already on the screen, and only updating the parts
  15.  * that changed.
  16.  *
  17.  * ScreenLines[] contains a copy of the whole screen, as it is currently
  18.  * displayed (excluding text written by external commands).
  19.  * ScreenAttrs[] contains the associated attributes.
  20.  * LineOffset[] contains the offset into ScreenLines[] for each line.
  21.  * For double-byte characters, two consecutive bytes in ScreenLines[] can form
  22.  * one character which occupies two display cells.
  23.  * For UTF-8 a multi-byte character is converted to Unicode and stored in
  24.  * ScreenLinesUC[].  ScreenLines[] contains the first byte only.  For an ASCII
  25.  * character without composing chars ScreenLinesUC[] will be 0.  When the
  26.  * character occupies two display cells the next byte in ScreenLines[] is 0.
  27.  * ScreenLinesC1[] and ScreenLinesC2[] contain up to two composing characters
  28.  * (drawn on top of the first character).  They are 0 when not used.
  29.  * ScreenLines2[] is only used for euc-jp to store the second byte if the
  30.  * first byte is 0x8e (single-width character).
  31.  *
  32.  * The screen_*() functions write to the screen and handle updating
  33.  * ScreenLines[].
  34.  *
  35.  * update_screen() is the function that updates all windows and status lines.
  36.  * It is called form the main loop when must_redraw is non-zero.  It may be
  37.  * called from other places when an immediated screen update is needed.
  38.  *
  39.  * The part of the buffer that is displayed in a window is set with:
  40.  * - w_topline (first buffer line in window)
  41.  * - w_topfill (filler line above the first line)
  42.  * - w_leftcol (leftmost window cell in window),
  43.  * - w_skipcol (skipped window cells of first line)
  44.  *
  45.  * Commands that only move the cursor around in a window, do not need to take
  46.  * action to update the display.  The main loop will check if w_topline is
  47.  * valid and update it (scroll the window) when needed.
  48.  *
  49.  * Commands that scroll a window change w_topline and must call
  50.  * check_cursor() to move the cursor into the visible part of the window, and
  51.  * call redraw_later(VALID) to have the window displayed by update_screen()
  52.  * later.
  53.  *
  54.  * Commands that change text in the buffer must call changed_bytes() or
  55.  * changed_lines() to mark the area that changed and will require updating
  56.  * later.  The main loop will call update_screen(), which will update each
  57.  * window that shows the changed buffer.  This assumes text above the change
  58.  * can remain displayed as it is.  Text after the change may need updating for
  59.  * scrolling, folding and syntax highlighting.
  60.  *
  61.  * Commands that change how a window is displayed (e.g., setting 'list') or
  62.  * invalidate the contents of a window in another way (e.g., change fold
  63.  * settings), must call redraw_later(NOT_VALID) to have the whole window
  64.  * redisplayed by update_screen() later.
  65.  *
  66.  * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
  67.  * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
  68.  * buffer redisplayed by update_screen() later.
  69.  *
  70.  * Commands that move the window position must call redraw_later(NOT_VALID).
  71.  * TODO: should minimize redrawing by scrolling when possible.
  72.  *
  73.  * Commands that change everything (e.g., resizing the screen) must call
  74.  * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
  75.  *
  76.  * Things that are handled indirectly:
  77.  * - When messages scroll the screen up, msg_scrolled will be set and
  78.  *   update_screen() called to redraw.
  79.  */
  80.  
  81. #include "vim.h"
  82.  
  83. /*
  84.  * The attributes that are actually active for writing to the screen.
  85.  */
  86. static int    screen_attr = 0;
  87.  
  88. /*
  89.  * Positioning the cursor is reduced by remembering the last position.
  90.  * Mostly used by windgoto() and screen_char().
  91.  */
  92. static int    screen_cur_row, screen_cur_col;    /* last known cursor position */
  93.  
  94. #ifdef FEAT_SEARCH_EXTRA
  95. /*
  96.  * Struct used for highlighting 'hlsearch' matches for the last use search
  97.  * pattern or a ":match" item.
  98.  * For 'hlsearch' there is one pattern for all windows.  For ":match" there is
  99.  * a different pattern for each window.
  100.  */
  101. typedef struct
  102. {
  103.     regmmatch_T    rm;    /* points to the regexp program; contains last found
  104.                match (may continue in next line) */
  105.     buf_T    *buf;    /* the buffer to search for a match */
  106.     linenr_T    lnum;    /* the line to search for a match */
  107.     int        attr;    /* attributes to be used for a match */
  108.     int        attr_cur; /* attributes currently active in win_line() */
  109.     linenr_T    first_lnum;    /* first lnum to search for multi-line pat */
  110.     char_u    *startp; /* in win_line() points to char where HL starts */
  111.     char_u    *endp;     /* in win_line() points to char where HL ends */
  112. } match_T;
  113.  
  114. static match_T search_hl;    /* used for 'hlsearch' highlight matching */
  115. static match_T match_hl;    /* used for ":match" highlight matching */
  116. #endif
  117.  
  118. #ifdef FEAT_FOLDING
  119. static foldinfo_T win_foldinfo;    /* info for 'foldcolumn' */
  120. #endif
  121.  
  122. /*
  123.  * Buffer for one screen line (characters and attributes).
  124.  */
  125. static schar_T    *current_ScreenLine;
  126.  
  127. static void win_update __ARGS((win_T *wp));
  128. static void win_draw_end __ARGS((win_T *wp, int c1, int c2, int row, int endrow, enum hlf_value hl));
  129. #ifdef FEAT_FOLDING
  130. static void fold_line __ARGS((win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row));
  131. static void fill_foldcolumn __ARGS((char_u *p, win_T *wp, int closed, linenr_T lnum));
  132. static void copy_text_attr __ARGS((int off, char_u *buf, int len, int attr));
  133. #endif
  134. static int win_line __ARGS((win_T *, linenr_T, int, int));
  135. static int char_needs_redraw __ARGS((int off_from, int off_to, int cols));
  136. #ifdef FEAT_RIGHTLEFT
  137. static void screen_line __ARGS((int row, int coloff, int endcol, int clear_width, int rlflag));
  138. # define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c), (rl))
  139. #else
  140. static void screen_line __ARGS((int row, int coloff, int endcol, int clear_width));
  141. # define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c))
  142. #endif
  143. #if defined(FEAT_WILDMENU) && defined(FEAT_VERTSPLIT)
  144. static void win_redraw_last_status __ARGS((frame_T *frp));
  145. #endif
  146. #ifdef FEAT_VERTSPLIT
  147. static void draw_vsep_win __ARGS((win_T *wp, int row));
  148. #endif
  149. #ifdef FEAT_SEARCH_EXTRA
  150. static void start_search_hl __ARGS((void));
  151. static void end_search_hl __ARGS((void));
  152. static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
  153. static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol));
  154. #endif
  155. static void screen_start_highlight __ARGS((int attr));
  156. static void screen_char __ARGS((unsigned off, int row, int col));
  157. #ifdef FEAT_MBYTE
  158. static void screen_char_2 __ARGS((unsigned off, int row, int col));
  159. #endif
  160. static void screenclear2 __ARGS((void));
  161. static void lineclear __ARGS((unsigned off, int width));
  162. static void lineinvalid __ARGS((unsigned off, int width));
  163. #ifdef FEAT_VERTSPLIT
  164. static void linecopy __ARGS((int to, int from, win_T *wp));
  165. static void redraw_block __ARGS((int row, int end, win_T *wp));
  166. #endif
  167. static int win_do_lines __ARGS((win_T *wp, int row, int line_count, int mayclear, int del));
  168. static void win_rest_invalid __ARGS((win_T *wp));
  169. static int screen_ins_lines __ARGS((int, int, int, int, win_T *wp));
  170. static void msg_pos_mode __ARGS((void));
  171. #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
  172. static int fillchar_status __ARGS((int *attr, int is_curwin));
  173. #endif
  174. #ifdef FEAT_VERTSPLIT
  175. static int fillchar_vsep __ARGS((int *attr));
  176. #endif
  177. #ifdef FEAT_STL_OPT
  178. static void win_redr_custom __ARGS((win_T *wp, int Ruler));
  179. #endif
  180. #ifdef FEAT_CMDL_INFO
  181. static void win_redr_ruler __ARGS((win_T *wp, int always));
  182. #endif
  183.  
  184. #if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT)
  185. /* Ugly global: overrule attribute used by screen_char() */
  186. static int screen_char_attr = 0;
  187. #endif
  188.  
  189. /*
  190.  * Redraw the current window later, with update_screen(type).
  191.  * Set must_redraw only if not already set to a higher value.
  192.  * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
  193.  */
  194.     void
  195. redraw_later(type)
  196.     int        type;
  197. {
  198.     redraw_win_later(curwin, type);
  199. }
  200.  
  201.     void
  202. redraw_win_later(wp, type)
  203.     win_T    *wp;
  204.     int        type;
  205. {
  206.     if (wp->w_redr_type < type)
  207.     {
  208.     wp->w_redr_type = type;
  209.     if (type >= NOT_VALID)
  210.         wp->w_lines_valid = 0;
  211.     if (must_redraw < type)    /* must_redraw is the maximum of all windows */
  212.         must_redraw = type;
  213.     }
  214. }
  215.  
  216. /*
  217.  * Force a complete redraw later.  Also resets the highlighting.  To be used
  218.  * after executing a shell command that messes up the screen.
  219.  */
  220.     void
  221. redraw_later_clear()
  222. {
  223.     redraw_all_later(CLEAR);
  224.     screen_attr = HL_BOLD | HL_UNDERLINE;
  225. }
  226.  
  227. /*
  228.  * Mark all windows to be redrawn later.
  229.  */
  230.     void
  231. redraw_all_later(type)
  232.     int        type;
  233. {
  234.     win_T    *wp;
  235.  
  236.     FOR_ALL_WINDOWS(wp)
  237.     {
  238.     redraw_win_later(wp, type);
  239.     }
  240. }
  241.  
  242. /*
  243.  * Mark all windows that are editing the current buffer to be udpated later.
  244.  */
  245.     void
  246. redraw_curbuf_later(type)
  247.     int        type;
  248. {
  249.     redraw_buf_later(curbuf, type);
  250. }
  251.  
  252.     void
  253. redraw_buf_later(buf, type)
  254.     buf_T    *buf;
  255.     int        type;
  256. {
  257.     win_T    *wp;
  258.  
  259.     FOR_ALL_WINDOWS(wp)
  260.     {
  261.     if (wp->w_buffer == buf)
  262.         redraw_win_later(wp, type);
  263.     }
  264. }
  265.  
  266. /*
  267.  * Changed something in the current window, at buffer line "lnum", that
  268.  * requires that line and possibly other lines to be redrawn.
  269.  * Used when entering/leaving Insert mode with the cursor on a folded line.
  270.  * Used to remove the "$" from a change command.
  271.  * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
  272.  * may become invalid and the whole window will have to be redrawn.
  273.  */
  274. /*ARGSUSED*/
  275.     void
  276. redrawWinline(lnum, invalid)
  277.     linenr_T    lnum;
  278.     int        invalid;    /* window line height is invalid now */
  279. {
  280. #ifdef FEAT_FOLDING
  281.     int        i;
  282. #endif
  283.  
  284.     if (curwin->w_redraw_top == 0 || curwin->w_redraw_top > lnum)
  285.     curwin->w_redraw_top = lnum;
  286.     if (curwin->w_redraw_bot == 0 || curwin->w_redraw_bot < lnum)
  287.     curwin->w_redraw_bot = lnum;
  288.     redraw_later(VALID);
  289.  
  290. #ifdef FEAT_FOLDING
  291.     if (invalid)
  292.     {
  293.     /* A w_lines[] entry for this lnum has become invalid. */
  294.     i = find_wl_entry(curwin, lnum);
  295.     if (i >= 0)
  296.         curwin->w_lines[i].wl_valid = FALSE;
  297.     }
  298. #endif
  299. }
  300.  
  301. /*
  302.  * update all windows that are editing the current buffer
  303.  */
  304.     void
  305. update_curbuf(type)
  306.     int        type;
  307. {
  308.     redraw_curbuf_later(type);
  309.     update_screen(type);
  310. }
  311.  
  312. /*
  313.  * update_screen()
  314.  *
  315.  * Based on the current value of curwin->w_topline, transfer a screenfull
  316.  * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
  317.  */
  318.     void
  319. update_screen(type)
  320.     int        type;
  321. {
  322.     win_T    *wp;
  323.     static int    did_intro = FALSE;
  324. #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
  325.     int        did_one;
  326. #endif
  327.  
  328.     if (!screen_valid(TRUE))
  329.     return;
  330.  
  331.     if (must_redraw)
  332.     {
  333.     if (type < must_redraw)        /* use maximal type */
  334.         type = must_redraw;
  335.     must_redraw = 0;
  336.     }
  337.  
  338.     /* Need to update w_lines[]. */
  339.     if (curwin->w_lines_valid == 0 && type < NOT_VALID)
  340.     type = NOT_VALID;
  341.  
  342.     if (!redrawing())
  343.     {
  344.     redraw_later(type);        /* remember type for next time */
  345.     must_redraw = type;
  346.     if (type > INVERTED_ALL)
  347.         curwin->w_lines_valid = 0;    /* don't use w_lines[].wl_size now */
  348.     return;
  349.     }
  350.  
  351. #ifdef FEAT_GUI
  352.     updating_screen = TRUE;
  353. #endif
  354. #ifdef FEAT_SYN_HL
  355.     ++display_tick;        /* let syntax code know we're in a next round of
  356.                  * display updating */
  357. #endif
  358.  
  359.     /*
  360.      * if the screen was scrolled up when displaying a message, scroll it down
  361.      */
  362.     if (msg_scrolled)
  363.     {
  364.     clear_cmdline = TRUE;
  365.     if (msg_scrolled > Rows - 5)        /* clearing is faster */
  366.         type = CLEAR;
  367.     else if (type != CLEAR)
  368.     {
  369.         check_for_delay(FALSE);
  370.         if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL)
  371.         type = CLEAR;
  372.         FOR_ALL_WINDOWS(wp)
  373.         {
  374.         if (W_WINROW(wp) < msg_scrolled)
  375.         {
  376.             if (W_WINROW(wp) + wp->w_height > msg_scrolled
  377.                 && wp->w_redr_type < REDRAW_TOP)
  378.             {
  379.             wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
  380.             wp->w_redr_type = REDRAW_TOP;
  381.             }
  382.             else
  383.             {
  384.             wp->w_redr_type = NOT_VALID;
  385. #ifdef FEAT_WINDOWS
  386.             if (W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp)
  387.                 <= msg_scrolled)
  388.                 wp->w_redr_status = TRUE;
  389. #endif
  390.             }
  391.         }
  392.         }
  393.         redraw_cmdline = TRUE;
  394.     }
  395.     msg_scrolled = 0;
  396.     need_wait_return = FALSE;
  397.     }
  398.  
  399.     /* reset cmdline_row now (may have been changed temporarily) */
  400.     compute_cmdrow();
  401.  
  402.     /* Check for changed highlighting */
  403.     if (need_highlight_changed)
  404.     highlight_changed();
  405.  
  406.     if (type == CLEAR)        /* first clear screen */
  407.     {
  408.     screenclear();        /* will reset clear_cmdline */
  409.     type = NOT_VALID;
  410.     }
  411.  
  412.     if (clear_cmdline)        /* first clear cmdline */
  413.     {
  414.     check_for_delay(FALSE);
  415.     msg_clr_cmdline();    /* will reset clear_cmdline */
  416.     }
  417.  
  418.     /*
  419.      * Only start redrawing if there is really something to do.
  420.      */
  421.     if (type == INVERTED)
  422.     update_curswant();
  423.     if (curwin->w_redr_type < type
  424.         && !((type == VALID
  425.             && curwin->w_lines[0].wl_valid
  426. #ifdef FEAT_DIFF
  427.             && curwin->w_topfill == curwin->w_old_topfill
  428.             && curwin->w_botfill == curwin->w_old_botfill
  429. #endif
  430.             && curwin->w_topline == curwin->w_lines[0].wl_lnum)
  431. #ifdef FEAT_VISUAL
  432.         || (type == INVERTED
  433.             && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
  434.             && curwin->w_old_visual_mode == VIsual_mode
  435.             && (curwin->w_valid & VALID_VIRTCOL)
  436.             && curwin->w_old_curswant == curwin->w_curswant)
  437. #endif
  438.         ))
  439.     curwin->w_redr_type = type;
  440.  
  441. #ifdef FEAT_SYN_HL
  442.     /*
  443.      * Correct stored syntax highlighting info for changes in each displayed
  444.      * buffer.  Each buffer must only be done once.
  445.      */
  446.     FOR_ALL_WINDOWS(wp)
  447.     {
  448.     if (wp->w_buffer->b_mod_set)
  449.     {
  450. # ifdef FEAT_WINDOWS
  451.         win_T    *wwp;
  452.  
  453.         /* Check if we already did this buffer. */
  454.         for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
  455.         if (wwp->w_buffer == wp->w_buffer)
  456.             break;
  457. # endif
  458.         if (
  459. # ifdef FEAT_WINDOWS
  460.             wwp == wp &&
  461. # endif
  462.             syntax_present(wp->w_buffer))
  463.         syn_stack_apply_changes(wp->w_buffer);
  464.     }
  465.     }
  466. #endif
  467.  
  468.     /*
  469.      * Go from top to bottom through the windows, redrawing the ones that need
  470.      * it.
  471.      */
  472. #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
  473.     did_one = FALSE;
  474. #endif
  475. #ifdef FEAT_SEARCH_EXTRA
  476.     search_hl.rm.regprog = NULL;
  477. #endif
  478.     FOR_ALL_WINDOWS(wp)
  479.     {
  480.     if (wp->w_redr_type != 0)
  481.     {
  482.         cursor_off();
  483. #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
  484.         if (!did_one)
  485.         {
  486.         did_one = TRUE;
  487. # ifdef FEAT_SEARCH_EXTRA
  488.         start_search_hl();
  489. # endif
  490. # ifdef FEAT_CLIPBOARD
  491.         /* When Visual area changed, may have to update selection. */
  492.         if (clip_star.available && clip_isautosel())
  493.             clip_update_selection();
  494. # endif
  495. #ifdef FEAT_GUI
  496.         /* Remove the cursor before starting to do anything, because
  497.          * scrolling may make it difficult to redraw the text under
  498.          * it. */
  499.         if (gui.in_use)
  500.             gui_undraw_cursor();
  501. #endif
  502.         }
  503. #endif
  504.         win_update(wp);
  505.     }
  506.  
  507. #ifdef FEAT_WINDOWS
  508.     /* redraw status line after the window to minimize cursor movement */
  509.     if (wp->w_redr_status)
  510.     {
  511.         cursor_off();
  512.         win_redr_status(wp);
  513.     }
  514. #endif
  515.     }
  516. #if defined(FEAT_SEARCH_EXTRA)
  517.     end_search_hl();
  518. #endif
  519.  
  520. #ifdef FEAT_WINDOWS
  521.     /* Reset b_mod_set flags.  Going through all windows is probably faster
  522.      * than going through all buffers (there could be many buffers). */
  523.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  524.     wp->w_buffer->b_mod_set = FALSE;
  525. #else
  526.     curbuf->b_mod_set = FALSE;
  527. #endif
  528.  
  529. #ifdef FEAT_GUI
  530.     updating_screen = FALSE;
  531.     gui_may_resize_shell();
  532. #endif
  533.  
  534.     if (redraw_cmdline)
  535.     showmode();
  536.  
  537.     /* May put up an introductory message when not editing a file */
  538.     if (!did_intro && bufempty()
  539.         && curbuf->b_fname == NULL
  540. #ifdef FEAT_WINDOWS
  541.         && firstwin->w_next == NULL
  542. #endif
  543.         && vim_strchr(p_shm, SHM_INTRO) == NULL)
  544.     intro_message(FALSE);
  545.     did_intro = TRUE;
  546.  
  547. #ifdef FEAT_GUI
  548.     /* Redraw the cursor and update the scrollbars when all screen updating is
  549.      * done. */
  550.     if (gui.in_use)
  551.     {
  552.     out_flush();    /* required before updating the cursor */
  553.     if (did_one)
  554.         gui_update_cursor(FALSE, FALSE);
  555.     gui_update_scrollbars(FALSE);
  556.     }
  557. #endif
  558. }
  559.  
  560. #if defined(FEAT_SIGNS) || defined(PROTO)
  561.     void
  562. update_debug_sign(buf, lnum)
  563.     buf_T    *buf;
  564.     linenr_T    lnum;
  565. {
  566.     win_T    *wp;
  567.     int        row;
  568.     int        j;
  569.  
  570. #ifdef FEAT_FOLDING
  571.     win_foldinfo.fi_level = 0;
  572. #endif
  573.  
  574. #ifdef FEAT_GUI
  575.     /* Remove the cursor before starting to do anything, because scrolling may
  576.      * make it difficult to redraw the text under it. */
  577.     if (gui.in_use)
  578.     gui_undraw_cursor();
  579. #endif
  580.     if (buf != NULL && lnum > 0)
  581.     {                    /* update/delete a specific mark */
  582.     FOR_ALL_WINDOWS(wp)
  583.     {
  584.         if (wp->w_buffer == buf && lnum >= wp->w_topline
  585.                               && lnum < wp->w_botline)
  586.         {
  587.         row = 0;
  588.         for (j = 0; j < wp->w_lines_valid; ++j)
  589.         {
  590.             /* Ignore folding, a closed fold with a sign doesn't need
  591.              * updating. */
  592.             if (lnum == wp->w_lines[j].wl_lnum)
  593.             {
  594.             screen_start();    /* not sure of screen cursor */
  595.             win_line(wp, lnum, row, row + wp->w_lines[j].wl_size);
  596.             break;
  597.             }
  598.             row += wp->w_lines[j].wl_size;
  599.         }
  600.         }
  601.     }
  602.     }
  603.     else
  604.     {
  605.     /* update all windows (signs deleted) */
  606. #ifdef FEAT_WINDOWS
  607.     for (wp = firstwin; wp; wp = wp->w_next)
  608.         win_update(wp);
  609. #else
  610.         win_update(curwin);
  611. #endif
  612.     }
  613. #ifdef FEAT_GUI
  614.     /* Redraw the cursor and update the scrollbars when all screen updating is
  615.      * done. */
  616.     if (gui.in_use)
  617.     {
  618.     out_flush();    /* required before updating the cursor */
  619.     gui_update_cursor(FALSE, FALSE);
  620.     gui_update_scrollbars(FALSE);
  621.     }
  622. #endif
  623. }
  624. #endif
  625.  
  626.  
  627. #ifdef FEAT_GUI
  628. /*
  629.  * Update a single window, its status line and maybe the command line msg.
  630.  * Used for the GUI scrollbar.
  631.  */
  632.     void
  633. updateWindow(wp)
  634.     win_T    *wp;
  635. {
  636.     cursor_off();
  637.     updating_screen = TRUE;
  638. #ifdef FEAT_GUI
  639.     /* Remove the cursor before starting to do anything, because scrolling may
  640.      * make it difficult to redraw the text under it. */
  641.     if (gui.in_use)
  642.     gui_undraw_cursor();
  643. #endif
  644. #ifdef FEAT_SEARCH_EXTRA
  645.     start_search_hl();
  646. #endif
  647. #ifdef FEAT_CLIPBOARD
  648.     /* When Visual area changed, may have to update selection. */
  649.     if (clip_star.available && clip_isautosel())
  650.     clip_update_selection();
  651. #endif
  652.     win_update(wp);
  653. #ifdef FEAT_WINDOWS
  654.     if (wp->w_redr_status
  655. # ifdef FEAT_CMDL_INFO
  656.         || p_ru
  657. # endif
  658. # ifdef FEAT_STL_OPT
  659.         || *p_stl
  660. # endif
  661.         )
  662.     win_redr_status(wp);
  663. #endif
  664.     if (redraw_cmdline)
  665.     showmode();
  666. #ifdef FEAT_SEARCH_EXTRA
  667.     end_search_hl();
  668. #endif
  669.     updating_screen = FALSE;
  670.     gui_may_resize_shell();
  671.  
  672. #ifdef FEAT_GUI
  673.     /* Redraw the cursor and update the scrollbars when all screen updating is
  674.      * done. */
  675.     if (gui.in_use)
  676.     {
  677.     out_flush();    /* required before updating the cursor */
  678.     gui_update_cursor(FALSE, FALSE);
  679.     gui_update_scrollbars(FALSE);
  680.     }
  681. #endif
  682. }
  683. #endif
  684.  
  685. /*
  686.  * Update a single window.
  687.  *
  688.  * This may cause the windows below it also to be redrawn (when clearing the
  689.  * screen or scrolling lines).
  690.  *
  691.  * How the window is redrawn depends on wp->w_redr_type.  Each type also
  692.  * implies the one below it.
  693.  * NOT_VALID    redraw the whole window
  694.  * REDRAW_TOP    redraw the top w_upd_rows window lines, otherwise like VALID
  695.  * INVERTED    redraw the changed part of the Visual area
  696.  * INVERTED_ALL    redraw the whole Visual area
  697.  * VALID    1. scroll up/down to adjust for a changed w_topline
  698.  *        2. update lines at the top when scrolled down
  699.  *        3. redraw changed text:
  700.  *           - if wp->w_buffer->b_mod_set set, udpate lines between
  701.  *             b_mod_top and b_mod_bot.
  702.  *           - if wp->w_redraw_top non-zero, redraw lines between
  703.  *             wp->w_redraw_top and wp->w_redr_bot.
  704.  *           - continue redrawing when syntax status is invalid.
  705.  *        4. if scrolled up, update lines at the bottom.
  706.  * This results in three areas that may need updating:
  707.  * top:    from first row to top_end (when scrolled down)
  708.  * mid: from mid_start to mid_end (update inversion or changed text)
  709.  * bot: from bot_start to last row (when scrolled up)
  710.  */
  711.     static void
  712. win_update(wp)
  713.     win_T    *wp;
  714. {
  715.     buf_T    *buf = wp->w_buffer;
  716.     int        type;
  717.     int        top_end = 0;    /* Below last row of the top area that needs
  718.                    updating.  0 when no top area updating. */
  719.     int        mid_start = 999;/* first row of the mid area that needs
  720.                    updating.  999 when no mid area updating. */
  721.     int        mid_end = 0;    /* Below last row of the mid area that needs
  722.                    updating.  0 when no mid area updating. */
  723.     int        bot_start = 999;/* first row of the bot area that needs
  724.                    updating.  999 when no bot area updating */
  725. #ifdef FEAT_VISUAL
  726.     int        scrolled_down = FALSE;    /* TRUE when scrolled down when
  727.                        w_topline got smaller a bit */
  728. #endif
  729. #ifdef FEAT_SEARCH_EXTRA
  730.     int        top_to_mod = FALSE;    /* redraw above mod_top */
  731. #endif
  732.  
  733.     int        row;        /* current window row to display */
  734.     linenr_T    lnum;        /* current buffer lnum to display */
  735.     int        idx;        /* current index in w_lines[] */
  736.     int        srow;        /* starting row of the current line */
  737.  
  738.     int        eof = FALSE;    /* if TRUE, we hit the end of the file */
  739.     int        didline = FALSE; /* if TRUE, we finished the last line */
  740.     int        i;
  741.     long    j;
  742.     static int    recursive = FALSE;    /* being called recursively */
  743.     int        old_botline = wp->w_botline;
  744. #ifdef FEAT_FOLDING
  745.     long    fold_count;
  746. #endif
  747. #ifdef FEAT_SYN_HL
  748.     /* remember what happened to the previous line, to know if
  749.      * check_visual_highlight() can be used */
  750. #define DID_NONE 1    /* didn't update a line */
  751. #define DID_LINE 2    /* updated a normal line */
  752. #define DID_FOLD 3    /* updated a folded line */
  753.     int        did_update = DID_NONE;
  754.     linenr_T    syntax_last_parsed = 0;        /* last parsed text line */
  755. #endif
  756.     linenr_T    mod_top = 0;
  757.     linenr_T    mod_bot = 0;
  758. #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
  759.     int        save_got_int;
  760. #endif
  761.  
  762.     type = wp->w_redr_type;
  763.  
  764.     if (type == NOT_VALID)
  765.     {
  766. #ifdef FEAT_WINDOWS
  767.     wp->w_redr_status = TRUE;
  768. #endif
  769.     wp->w_lines_valid = 0;
  770.     }
  771.  
  772.     /* Window is zero-height: nothing to draw. */
  773.     if (wp->w_height == 0)
  774.     {
  775.     wp->w_redr_type = 0;
  776.     return;
  777.     }
  778.  
  779. #ifdef FEAT_VERTSPLIT
  780.     /* Window is zero-width: Only need to draw the separator. */
  781.     if (wp->w_width == 0)
  782.     {
  783.     /* draw the vertical separator right of this window */
  784.     draw_vsep_win(wp, 0);
  785.     wp->w_redr_type = 0;
  786.     return;
  787.     }
  788. #endif
  789.  
  790. #ifdef FEAT_SEARCH_EXTRA
  791.     /* Setup for ":match" highlighting.  Disable any previous match */
  792.     match_hl.rm = wp->w_match;
  793.     if (wp->w_match_id == 0)
  794.     match_hl.attr = 0;
  795.     else
  796.     match_hl.attr = syn_id2attr(wp->w_match_id);
  797.     match_hl.buf = buf;
  798.     match_hl.lnum = 0;
  799.     search_hl.buf = buf;
  800.     search_hl.lnum = 0;
  801.     search_hl.first_lnum = 0;
  802. #endif
  803.  
  804.     if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
  805.     {
  806.     /*
  807.      * When there are both inserted/deleted lines and specific lines to be
  808.      * redrawn,, w_redraw_top and w_redraw_bot may be invalid, just redraw
  809.      * everything (only happens when redrawing is off for while).
  810.      */
  811.     type = NOT_VALID;
  812.     }
  813.     else
  814.     {
  815.     /*
  816.      * Set mod_top to the first line that needs displaying because of
  817.      * changes.  Set mod_bot to the first line after the changes.
  818.      */
  819.     mod_top = wp->w_redraw_top;
  820.     if (wp->w_redraw_bot != 0)
  821.         mod_bot = wp->w_redraw_bot + 1;
  822.     else
  823.         mod_bot = 0;
  824.     wp->w_redraw_top = 0;    /* reset for next time */
  825.     wp->w_redraw_bot = 0;
  826.     if (buf->b_mod_set)
  827.     {
  828.         if (mod_top == 0 || mod_top > buf->b_mod_top)
  829.         mod_top = buf->b_mod_top;
  830.         if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
  831.         mod_bot = buf->b_mod_bot;
  832.  
  833. #ifdef FEAT_SEARCH_EXTRA
  834.         /* When 'hlsearch' is on and using a multi-line search pattern, a
  835.          * change in one line may make the Search highlighting in a
  836.          * previous line invalid.  Simple solution: redraw all visible
  837.          * lines above the change.
  838.          * Same for a ":match" pattern.
  839.          */
  840.         if ((search_hl.rm.regprog != NULL
  841.             && re_multiline(search_hl.rm.regprog))
  842.             || (match_hl.rm.regprog != NULL
  843.             && re_multiline(match_hl.rm.regprog)))
  844.         top_to_mod = TRUE;
  845. #endif
  846.     }
  847. #ifdef FEAT_FOLDING
  848.     if (mod_top != 0 && hasAnyFolding(wp))
  849.     {
  850.         linenr_T    lnumt, lnumb;
  851.  
  852.         /*
  853.          * A change in a line can cause lines above it to become folded or
  854.          * unfolded.  Find the top most buffer line that may be affected.
  855.          * If the line was previously folded and displayed, get the first
  856.          * line of that fold.  If the line is folded now, get the first
  857.          * folded line.  Use the minimum of these two.
  858.          */
  859.  
  860.         /* Find last valid w_lines[] entry above mod_top.  Set lnumt to
  861.          * the line below it.  If there is no valid entry, use w_topline.
  862.          * Find the first valid w_lines[] entry below mod_bot.  Set lnumb
  863.          * to this line.  If there is no valid entry, use MAXLNUM. */
  864.         lnumt = wp->w_topline;
  865.         lnumb = MAXLNUM;
  866.         for (i = 0; i < wp->w_lines_valid; ++i)
  867.         if (wp->w_lines[i].wl_valid)
  868.         {
  869.             if (wp->w_lines[i].wl_lastlnum < mod_top)
  870.             lnumt = wp->w_lines[i].wl_lastlnum + 1;
  871.             if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
  872.             {
  873.             lnumb = wp->w_lines[i].wl_lnum;
  874.             /* When there is a fold column it might need updating
  875.              * in the next line ("J" just above an open fold). */
  876.             if (wp->w_p_fdc > 0)
  877.                 ++lnumb;
  878.             }
  879.         }
  880.  
  881.         (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
  882.         if (mod_top > lnumt)
  883.         mod_top = lnumt;
  884.  
  885.         /* Now do the same for the bottom line (one above mod_bot). */
  886.         --mod_bot;
  887.         (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
  888.         ++mod_bot;
  889.         if (mod_bot < lnumb)
  890.         mod_bot = lnumb;
  891.     }
  892. #endif
  893.  
  894.     /* When a change starts above w_topline and the end is below
  895.      * w_topline, start redrawing at w_topline.
  896.      * If the end of the change is above w_topline: do like no changes was
  897.      * maded, but redraw the first line to find changes in syntax. */
  898.     if (mod_top != 0 && mod_top < wp->w_topline)
  899.     {
  900.         if (mod_bot > wp->w_topline)
  901.         mod_top = wp->w_topline;
  902. #ifdef FEAT_SYN_HL
  903.         else if (syntax_present(buf))
  904.         top_end = 1;
  905. #endif
  906.     }
  907.     }
  908.  
  909.     /*
  910.      * When only displaying the lines at the top, set top_end.  Used when
  911.      * window has scrolled down for msg_scrolled.
  912.      */
  913.     if (type == REDRAW_TOP)
  914.     {
  915.     j = 0;
  916.     for (i = 0; i < wp->w_lines_valid; ++i)
  917.     {
  918.         j += wp->w_lines[i].wl_size;
  919.         if (j >= wp->w_upd_rows)
  920.         {
  921.         top_end = j;
  922.         break;
  923.         }
  924.     }
  925.     if (top_end == 0)
  926.         /* not found (cannot happen?): redraw everything */
  927.         type = NOT_VALID;
  928.     else
  929.         /* top area defined, the rest is VALID */
  930.         type = VALID;
  931.     }
  932.  
  933.     /*
  934.      * If there are no changes on the screen that require a complete redraw,
  935.      * handle three cases:
  936.      * 1: we are off the top of the screen by a few lines: scroll down
  937.      * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
  938.      * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
  939.      *    w_lines[] that needs updating.
  940.      */
  941.     if ((type == VALID || type == INVERTED || type == INVERTED_ALL)
  942. #ifdef FEAT_DIFF
  943.         && !wp->w_botfill && !wp->w_old_botfill
  944. #endif
  945.         )
  946.     {
  947.     if (buf->b_mod_set && wp->w_topline == mod_top)
  948.     {
  949.         /*
  950.          * w_topline is the first changed line, the scrolling will be done
  951.          * further down.
  952.          */
  953.     }
  954.     else if (wp->w_lines[0].wl_valid
  955.         && (wp->w_topline < wp->w_lines[0].wl_lnum
  956. #ifdef FEAT_DIFF
  957.             || (wp->w_topline == wp->w_lines[0].wl_lnum
  958.             && wp->w_topfill > wp->w_old_topfill)
  959. #endif
  960.            ))
  961.     {
  962.         /*
  963.          * New topline is above old topline: May scroll down.
  964.          */
  965. #ifdef FEAT_FOLDING
  966.         if (hasAnyFolding(wp))
  967.         {
  968.         linenr_T ln;
  969.  
  970.         /* count the number of lines we are off, counting a sequence
  971.          * of folded lines as one */
  972.         j = 0;
  973.         for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
  974.         {
  975.             ++j;
  976.             if (j >= wp->w_height - 2)
  977.             break;
  978.             (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
  979.         }
  980.         }
  981.         else
  982. #endif
  983.         j = wp->w_lines[0].wl_lnum - wp->w_topline;
  984.         if (j < wp->w_height - 2)        /* not too far off */
  985.         {
  986.         i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
  987. #ifdef FEAT_DIFF
  988.         /* insert extra lines for previously invisible filler lines */
  989.         if (wp->w_lines[0].wl_lnum != wp->w_topline)
  990.             i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
  991.                               - wp->w_old_topfill;
  992. #endif
  993.         if (i < wp->w_height - 2)    /* less than a screen off */
  994.         {
  995.             /*
  996.              * Try to insert the correct number of lines.
  997.              * If not the last window, delete the lines at the bottom.
  998.              * win_ins_lines may fail when the terminal can't do it.
  999.              */
  1000.             if (i > 0)
  1001.             check_for_delay(FALSE);
  1002.             if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
  1003.             {
  1004.             if (wp->w_lines_valid != 0)
  1005.             {
  1006.                 /* Need to update rows that are new, stop at the
  1007.                  * first one that scrolled down. */
  1008.                 top_end = i;
  1009. #ifdef FEAT_VISUAL
  1010.                 scrolled_down = TRUE;
  1011. #endif
  1012.  
  1013.                 /* Move the entries that were scrolled, disable
  1014.                  * the entries for the lines to be redrawn. */
  1015.                 if ((wp->w_lines_valid += j) > wp->w_height)
  1016.                 wp->w_lines_valid = wp->w_height;
  1017.                 for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
  1018.                 wp->w_lines[idx] = wp->w_lines[idx - j];
  1019.                 while (idx >= 0)
  1020.                 wp->w_lines[idx--].wl_valid = FALSE;
  1021.             }
  1022.             }
  1023.             else
  1024.             mid_start = 0;        /* redraw all lines */
  1025.         }
  1026.         else
  1027.             mid_start = 0;        /* redraw all lines */
  1028.         }
  1029.         else
  1030.         mid_start = 0;        /* redraw all lines */
  1031.     }
  1032.     else
  1033.     {
  1034.         /*
  1035.          * New topline is at or below old topline: May scroll up.
  1036.          * When topline didn't change, find first entry in w_lines[] that
  1037.          * needs updating.
  1038.          */
  1039.  
  1040.         /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
  1041.         j = -1;
  1042.         row = 0;
  1043.         for (i = 0; i < wp->w_lines_valid; i++)
  1044.         {
  1045.         if (wp->w_lines[i].wl_valid
  1046.             && wp->w_lines[i].wl_lnum == wp->w_topline)
  1047.         {
  1048.             j = i;
  1049.             break;
  1050.         }
  1051.         row += wp->w_lines[i].wl_size;
  1052.         }
  1053.         if (j == -1)
  1054.         {
  1055.         /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
  1056.          * lines */
  1057.         mid_start = 0;
  1058.         }
  1059.         else
  1060.         {
  1061.         /*
  1062.          * Try to delete the correct number of lines.
  1063.          * wp->w_topline is at wp->w_lines[i].wl_lnum.
  1064.          */
  1065. #ifdef FEAT_DIFF
  1066.         /* If the topline didn't change, delete old filler lines,
  1067.          * otherwise delete filler lines of the new topline... */
  1068.         if (wp->w_lines[0].wl_lnum == wp->w_topline)
  1069.             row += wp->w_old_topfill;
  1070.         else
  1071.             row += diff_check_fill(wp, wp->w_topline);
  1072.         /* ... but don't delete new filler lines. */
  1073.         row -= wp->w_topfill;
  1074. #endif
  1075.         if (row > 0)
  1076.         {
  1077.             check_for_delay(FALSE);
  1078.             if (win_del_lines(wp, 0, row, FALSE, wp == firstwin) == OK)
  1079.             bot_start = wp->w_height - row;
  1080.             else
  1081.             mid_start = 0;        /* redraw all lines */
  1082.         }
  1083.         if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
  1084.         {
  1085.             /*
  1086.              * Skip the lines (below the deleted lines) that are still
  1087.              * valid and don't need redrawing.    Copy their info
  1088.              * upwards, to compensate for the deleted lines.  Set
  1089.              * bot_start to the first row that needs redrawing.
  1090.              */
  1091.             bot_start = 0;
  1092.             idx = 0;
  1093.             for (;;)
  1094.             {
  1095.             wp->w_lines[idx] = wp->w_lines[j];
  1096.             /* stop at line that didn't fit */
  1097.             if (bot_start + row + (int)wp->w_lines[j].wl_size
  1098.                                    > wp->w_height)
  1099.             {
  1100.                 wp->w_lines_valid = idx + 1;
  1101.                 break;
  1102.             }
  1103.             bot_start += wp->w_lines[idx++].wl_size;
  1104.  
  1105.             /* stop at the last valid entry in w_lines[].wl_size */
  1106.             if (++j >= wp->w_lines_valid)
  1107.             {
  1108.                 wp->w_lines_valid = idx;
  1109.                 break;
  1110.             }
  1111.             }
  1112. #ifdef FEAT_DIFF
  1113.             /* Correct the first entry for filler lines at the top
  1114.              * when it won't get updated below. */
  1115.             if (wp->w_p_diff && bot_start > 0)
  1116.             wp->w_lines[0].wl_size =
  1117.                 plines_win_nofill(wp, wp->w_topline, TRUE)
  1118.                                   + wp->w_topfill;
  1119. #endif
  1120.         }
  1121.         }
  1122.     }
  1123.  
  1124.     /* When starting redraw in the first line, redraw all lines.  When
  1125.      * there is only one window it's probably faster to clear the screen
  1126.      * first. */
  1127.     if (mid_start == 0)
  1128.     {
  1129.         mid_end = wp->w_height;
  1130.         if (lastwin == firstwin)
  1131.         screenclear();
  1132.     }
  1133.     }
  1134.     else
  1135.     {
  1136.     /* Not VALID or INVERTED: redraw all lines. */
  1137.     mid_start = 0;
  1138.     mid_end = wp->w_height;
  1139.     }
  1140.  
  1141. #ifdef FEAT_VISUAL
  1142.     /* check if we are updating or removing the inverted part */
  1143.     if ((VIsual_active && buf == curwin->w_buffer)
  1144.         || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
  1145.     {
  1146.     linenr_T    from, to;
  1147.  
  1148.     if (VIsual_active)
  1149.     {
  1150.         if (VIsual_active
  1151.             && (VIsual_mode != wp->w_old_visual_mode
  1152.             || type == INVERTED_ALL))
  1153.         {
  1154.         /*
  1155.          * If the type of Visual selection changed, redraw the whole
  1156.          * selection.  Also when the ownership of the X selection is
  1157.          * gained or lost.
  1158.          */
  1159.         if (curwin->w_cursor.lnum < VIsual.lnum)
  1160.         {
  1161.             from = curwin->w_cursor.lnum;
  1162.             to = VIsual.lnum;
  1163.         }
  1164.         else
  1165.         {
  1166.             from = VIsual.lnum;
  1167.             to = curwin->w_cursor.lnum;
  1168.         }
  1169.         /* redraw more when the cursor moved as well */
  1170.         if (wp->w_old_cursor_lnum < from)
  1171.             from = wp->w_old_cursor_lnum;
  1172.         if (wp->w_old_cursor_lnum > to)
  1173.             to = wp->w_old_cursor_lnum;
  1174.         }
  1175.         else
  1176.         {
  1177.         /*
  1178.          * Find the line numbers that need to be updated: The lines
  1179.          * between the old cursor position and the current cursor
  1180.          * position.  Also check if the Visual position changed.
  1181.          */
  1182.         if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
  1183.         {
  1184.             from = curwin->w_cursor.lnum;
  1185.             to = wp->w_old_cursor_lnum;
  1186.         }
  1187.         else
  1188.         {
  1189.             from = wp->w_old_cursor_lnum;
  1190.             to = curwin->w_cursor.lnum;
  1191.             if (from == 0)    /* Visual mode just started */
  1192.             from = to;
  1193.         }
  1194.  
  1195.         if (VIsual.lnum != wp->w_old_visual_lnum)
  1196.         {
  1197.             if (wp->w_old_visual_lnum < from
  1198.                         && wp->w_old_visual_lnum != 0)
  1199.             from = wp->w_old_visual_lnum;
  1200.             if (wp->w_old_visual_lnum > to)
  1201.             to = wp->w_old_visual_lnum;
  1202.             if (VIsual.lnum < from)
  1203.             from = VIsual.lnum;
  1204.             if (VIsual.lnum > to)
  1205.             to = VIsual.lnum;
  1206.         }
  1207.         }
  1208.  
  1209.         /*
  1210.          * If in block mode and changed column or curwin->w_curswant:
  1211.          * update all lines.
  1212.          * First compute the actual start and end column.
  1213.          */
  1214.         if (VIsual_mode == Ctrl_V)
  1215.         {
  1216.         colnr_T    fromc, toc;
  1217.  
  1218.         getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
  1219.         ++toc;
  1220.         if (curwin->w_curswant == MAXCOL)
  1221.             toc = MAXCOL;
  1222.  
  1223.         if (fromc != wp->w_old_cursor_fcol
  1224.             || toc != wp->w_old_cursor_lcol)
  1225.         {
  1226.             if (from > VIsual.lnum)
  1227.             from = VIsual.lnum;
  1228.             if (to < VIsual.lnum)
  1229.             to = VIsual.lnum;
  1230.         }
  1231.         wp->w_old_cursor_fcol = fromc;
  1232.         wp->w_old_cursor_lcol = toc;
  1233.         }
  1234.     }
  1235.     else
  1236.     {
  1237.         /* Use the line numbers of the old Visual area. */
  1238.         if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
  1239.         {
  1240.         from = wp->w_old_cursor_lnum;
  1241.         to = wp->w_old_visual_lnum;
  1242.         }
  1243.         else
  1244.         {
  1245.         from = wp->w_old_visual_lnum;
  1246.         to = wp->w_old_cursor_lnum;
  1247.         }
  1248.     }
  1249.  
  1250.     /*
  1251.      * There is no need to update lines above the top of the window.
  1252.      */
  1253.     if (from < wp->w_topline)
  1254.         from = wp->w_topline;
  1255.  
  1256.     /*
  1257.      * If we know the value of w_botline, use it to restrict the update to
  1258.      * the lines that are visible in the window.
  1259.      */
  1260.     if (wp->w_valid & VALID_BOTLINE)
  1261.     {
  1262.         if (from >= wp->w_botline)
  1263.         from = wp->w_botline - 1;
  1264.         if (to >= wp->w_botline)
  1265.         to = wp->w_botline - 1;
  1266.     }
  1267.  
  1268.     /*
  1269.      * Find the minimal part to be updated.
  1270.      * Watch out for scrolling that made entries in w_lines[] invalid.
  1271.      * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
  1272.      * top_end; need to redraw from top_end to the "to" line.
  1273.      * A middle mouse click with a Visual selection may change the text
  1274.      * above the Visual area and reset wl_valid, do count these for
  1275.      * mid_end (in srow).
  1276.      */
  1277.     if (mid_start > 0)
  1278.     {
  1279.         lnum = wp->w_topline;
  1280.         idx = 0;
  1281.         srow = 0;
  1282.         if (scrolled_down)
  1283.         mid_start = top_end;
  1284.         else
  1285.         mid_start = 0;
  1286.         while (lnum < from && idx < wp->w_lines_valid)    /* find start */
  1287.         {
  1288.         if (wp->w_lines[idx].wl_valid)
  1289.             mid_start += wp->w_lines[idx].wl_size;
  1290.         else if (!scrolled_down)
  1291.             srow += wp->w_lines[idx].wl_size;
  1292.         ++idx;
  1293. # ifdef FEAT_FOLDING
  1294.         if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
  1295.             lnum = wp->w_lines[idx].wl_lnum;
  1296.         else
  1297. # endif
  1298.             ++lnum;
  1299.         }
  1300.         srow += mid_start;
  1301.         mid_end = wp->w_height;
  1302.         for ( ; idx < wp->w_lines_valid; ++idx)        /* find end */
  1303.         {
  1304.         if (wp->w_lines[idx].wl_valid
  1305.             && wp->w_lines[idx].wl_lnum >= to + 1)
  1306.         {
  1307.             /* Only update until first row of this line */
  1308.             mid_end = srow;
  1309.             break;
  1310.         }
  1311.         srow += wp->w_lines[idx].wl_size;
  1312.         }
  1313.     }
  1314.     }
  1315.  
  1316.     if (VIsual_active && buf == curwin->w_buffer)
  1317.     {
  1318.     wp->w_old_visual_mode = VIsual_mode;
  1319.     wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
  1320.     wp->w_old_visual_lnum = VIsual.lnum;
  1321.     wp->w_old_curswant = curwin->w_curswant;
  1322.     }
  1323.     else
  1324.     {
  1325.     wp->w_old_visual_mode = 0;
  1326.     wp->w_old_cursor_lnum = 0;
  1327.     wp->w_old_visual_lnum = 0;
  1328.     }
  1329. #endif /* FEAT_VISUAL */
  1330.  
  1331. #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
  1332.     /* reset got_int, otherwise regexp won't work */
  1333.     save_got_int = got_int;
  1334.     got_int = 0;
  1335. #endif
  1336. #ifdef FEAT_FOLDING
  1337.     win_foldinfo.fi_level = 0;
  1338. #endif
  1339.  
  1340.     /*
  1341.      * Update all the window rows.
  1342.      */
  1343.     idx = 0;        /* first entry in w_lines[].wl_size */
  1344.     row = 0;
  1345.     srow = 0;
  1346.     lnum = wp->w_topline;    /* first line shown in window */
  1347.     for (;;)
  1348.     {
  1349.     /* stop updating when reached the end of the window (check for _past_
  1350.      * the end of the window is at the end of the loop) */
  1351.     if (row == wp->w_height)
  1352.     {
  1353.         didline = TRUE;
  1354.         break;
  1355.     }
  1356.  
  1357.     /* stop updating when hit the end of the file */
  1358.     if (lnum > buf->b_ml.ml_line_count)
  1359.     {
  1360.         eof = TRUE;
  1361.         break;
  1362.     }
  1363.  
  1364.     /* Remember the starting row of the line that is going to be dealt
  1365.      * with.  It is used further down when the line doesn't fit. */
  1366.     srow = row;
  1367.  
  1368.     /*
  1369.      * Update a line when it is in an area that needs updating, when it
  1370.      * has changes or w_lines[idx] is invalid.
  1371.      * bot_start may be halfway a wrapped line after using
  1372.      * win_del_lines(), check if the current line includes it.
  1373.      * When syntax folding is being used, the saved syntax states will
  1374.      * already have been updated, we can't see where the syntax state is
  1375.      * the same again, just update until the end of the window.
  1376.      */
  1377.     if (row < top_end
  1378.         || (row >= mid_start && row < mid_end)
  1379. #ifdef FEAT_SEARCH_EXTRA
  1380.         || top_to_mod
  1381. #endif
  1382.         || idx >= wp->w_lines_valid
  1383.         || (row + wp->w_lines[idx].wl_size > bot_start)
  1384.         || (mod_top != 0
  1385.             && (lnum == mod_top
  1386.             || (lnum >= mod_top
  1387.                 && (lnum < mod_bot
  1388. #ifdef FEAT_SYN_HL
  1389.                 || did_update == DID_FOLD
  1390.                 || (did_update == DID_LINE
  1391.                     && syntax_present(buf)
  1392.                     && (
  1393. # ifdef FEAT_FOLDING
  1394.                     (foldmethodIsSyntax(wp)
  1395.                               && hasAnyFolding(wp)) ||
  1396. # endif
  1397.                     syntax_check_changed(lnum)))
  1398. #endif
  1399.                 )))))
  1400.     {
  1401. #ifdef FEAT_SEARCH_EXTRA
  1402.         if (lnum == mod_top)
  1403.         top_to_mod = FALSE;
  1404. #endif
  1405.  
  1406.         /*
  1407.          * When at start of changed lines: May scroll following lines
  1408.          * up or down to minimize redrawing.
  1409.          * Don't do this when the change continues until the end.
  1410.          * Don't scroll when dollar_vcol is non-zero, keep the "$".
  1411.          */
  1412.         if (lnum == mod_top
  1413.             && mod_bot != MAXLNUM
  1414.             && !(dollar_vcol != 0 && mod_bot == mod_top + 1))
  1415.         {
  1416.         int        old_rows = 0;
  1417.         int        new_rows = 0;
  1418.         int        xtra_rows;
  1419.         linenr_T    l;
  1420.  
  1421.         /* Count the old number of window rows, using w_lines[], which
  1422.          * should still contain the sizes for the lines as they are
  1423.          * currently displayed. */
  1424.         for (i = idx; i < wp->w_lines_valid; ++i)
  1425.         {
  1426.             /* Only valid lines have a meaningful wl_lnum.  Invalid
  1427.              * lines are part of the changed area. */
  1428.             if (wp->w_lines[i].wl_valid
  1429.                 && wp->w_lines[i].wl_lnum == mod_bot)
  1430.             break;
  1431.             old_rows += wp->w_lines[i].wl_size;
  1432. #ifdef FEAT_FOLDING
  1433.             if (wp->w_lines[i].wl_valid
  1434.                 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
  1435.             {
  1436.             /* Must have found the last valid entry above mod_bot.
  1437.              * Add following invalid entries. */
  1438.             ++i;
  1439.             while (i < wp->w_lines_valid
  1440.                           && !wp->w_lines[i].wl_valid)
  1441.                 old_rows += wp->w_lines[i++].wl_size;
  1442.             break;
  1443.             }
  1444. #endif
  1445.         }
  1446.  
  1447.         if (i >= wp->w_lines_valid)
  1448.         {
  1449.             /* When buffer lines have been inserted/deleted, and
  1450.              * insering/deleting window lines is not possible, need to
  1451.              * check for redraw until the end of the window.  This is
  1452.              * also required when w_topline changed. */
  1453.             if (buf->b_mod_xlines != 0
  1454.                 || (wp->w_topline == mod_top
  1455.                 && wp->w_lines_valid > 0
  1456.                 && wp->w_lines[0].wl_lnum != mod_top))
  1457.             bot_start = 0;
  1458.         }
  1459.         else
  1460.         {
  1461.             /* Able to count old number of rows: Count new window
  1462.              * rows, and may insert/delete lines */
  1463.             j = idx;
  1464.             for (l = lnum; l < mod_bot; ++l)
  1465.             {
  1466. #ifdef FEAT_FOLDING
  1467.             if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
  1468.                 ++new_rows;
  1469.             else
  1470. #endif
  1471. #ifdef FEAT_DIFF
  1472.                 if (l == wp->w_topline)
  1473.                 new_rows += plines_win_nofill(wp, l, TRUE)
  1474.                                   + wp->w_topfill;
  1475.             else
  1476. #endif
  1477.                 new_rows += plines_win(wp, l, TRUE);
  1478.             ++j;
  1479.             if (new_rows > wp->w_height - row - 2)
  1480.             {
  1481.                 /* it's getting too much, must redraw the rest */
  1482.                 new_rows = 9999;
  1483.                 break;
  1484.             }
  1485.             }
  1486.             xtra_rows = new_rows - old_rows;
  1487.             if (xtra_rows < 0)
  1488.             {
  1489.             /* May scroll text up.  If there is not enough
  1490.              * remaining text or scrolling fails, must redraw the
  1491.              * rest.  If scrolling works, must redraw the text
  1492.              * below the scrolled text. */
  1493.             if (row - xtra_rows >= wp->w_height - 2)
  1494.                 mod_bot = MAXLNUM;
  1495.             else
  1496.             {
  1497.                 check_for_delay(FALSE);
  1498.                 if (win_del_lines(wp, row,
  1499.                         -xtra_rows, FALSE, FALSE) == FAIL)
  1500.                 mod_bot = MAXLNUM;
  1501.                 else
  1502.                 bot_start = wp->w_height + xtra_rows;
  1503.             }
  1504.             }
  1505.             else if (xtra_rows > 0)
  1506.             {
  1507.             /* May scroll text down.  If there is not enough
  1508.              * remaining text of scrolling fails, must redraw the
  1509.              * rest. */
  1510.             if (row + xtra_rows >= wp->w_height - 2)
  1511.                 mod_bot = MAXLNUM;
  1512.             else
  1513.             {
  1514.                 check_for_delay(FALSE);
  1515.                 if (win_ins_lines(wp, row + old_rows,
  1516.                          xtra_rows, FALSE, FALSE) == FAIL)
  1517.                 mod_bot = MAXLNUM;
  1518.                 else if (top_end > row + old_rows)
  1519.                 /* Scrolled the part at the top that requires
  1520.                  * updating down. */
  1521.                 top_end += xtra_rows;
  1522.             }
  1523.             }
  1524.  
  1525.             /* When not updating the rest, may need to move w_lines[]
  1526.              * entries. */
  1527.             if (mod_bot != MAXLNUM && i != j)
  1528.             {
  1529.             if (j < i)
  1530.             {
  1531.                 int x = row + new_rows;
  1532.  
  1533.                 /* move entries in w_lines[] upwards */
  1534.                 for (;;)
  1535.                 {
  1536.                 /* stop at last valid entry in w_lines[] */
  1537.                 if (i >= wp->w_lines_valid)
  1538.                 {
  1539.                     wp->w_lines_valid = j;
  1540.                     break;
  1541.                 }
  1542.                 wp->w_lines[j] = wp->w_lines[i];
  1543.                 /* stop at a line that won't fit */
  1544.                 if (x + (int)wp->w_lines[j].wl_size
  1545.                                > wp->w_height)
  1546.                 {
  1547.                     wp->w_lines_valid = j + 1;
  1548.                     break;
  1549.                 }
  1550.                 x += wp->w_lines[j++].wl_size;
  1551.                 ++i;
  1552.                 }
  1553.                 if (bot_start > x)
  1554.                 bot_start = x;
  1555.             }
  1556.             else /* j > i */
  1557.             {
  1558.                 /* move entries in w_lines[] downwards */
  1559.                 j -= i;
  1560.                 wp->w_lines_valid += j;
  1561.                 if (wp->w_lines_valid > wp->w_height)
  1562.                 wp->w_lines_valid = wp->w_height;
  1563.                 for (i = wp->w_lines_valid; i - j >= idx; --i)
  1564.                 wp->w_lines[i] = wp->w_lines[i - j];
  1565.             }
  1566.             }
  1567.         }
  1568.  
  1569.         /* When inserting or deleting lines and 'number' is set:
  1570.          * Redraw all lines below the change to update the line
  1571.          * numbers. */
  1572.         if (buf->b_mod_xlines != 0 && wp->w_p_nu)
  1573.             bot_start = 0;
  1574.         }
  1575.  
  1576. #ifdef FEAT_FOLDING
  1577.         /*
  1578.          * When lines are folded, display one line for all of them.
  1579.          * Otherwise, display normally (can be several display lines when
  1580.          * 'wrap' is on).
  1581.          */
  1582.         fold_count = foldedCount(wp, lnum, &win_foldinfo);
  1583.         if (fold_count != 0)
  1584.         {
  1585.         fold_line(wp, fold_count, &win_foldinfo, lnum, row);
  1586.         ++row;
  1587.         --fold_count;
  1588.         wp->w_lines[idx].wl_folded = TRUE;
  1589.         wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
  1590. #ifdef FEAT_SYN_HL
  1591.         did_update = DID_FOLD;
  1592. #endif
  1593.         }
  1594.         else
  1595. #endif
  1596.         {
  1597. #ifdef FEAT_SEARCH_EXTRA
  1598.         prepare_search_hl(wp, lnum);
  1599. #endif
  1600. #ifdef FEAT_SYN_HL
  1601.         /* Let the syntax stuff know we skipped a few lines. */
  1602.         if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
  1603.                                && syntax_present(buf))
  1604.             syntax_end_parsing(syntax_last_parsed + 1);
  1605. #endif
  1606.  
  1607.         /*
  1608.          * Display one line.
  1609.          */
  1610.         row = win_line(wp, lnum, srow, wp->w_height);
  1611.  
  1612. #ifdef FEAT_FOLDING
  1613.         wp->w_lines[idx].wl_folded = FALSE;
  1614.         wp->w_lines[idx].wl_lastlnum = lnum;
  1615. #endif
  1616. #ifdef FEAT_SYN_HL
  1617.         did_update = DID_LINE;
  1618.         syntax_last_parsed = lnum;
  1619. #endif
  1620.         }
  1621.  
  1622.         wp->w_lines[idx].wl_lnum = lnum;
  1623.         wp->w_lines[idx].wl_valid = TRUE;
  1624.         if (row > wp->w_height)    /* past end of screen */
  1625.         {
  1626.         /* we may need the size of that too long line later on */
  1627.         if (dollar_vcol == 0)
  1628.             wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
  1629.         ++idx;
  1630.         break;
  1631.         }
  1632.         if (dollar_vcol == 0)
  1633.         wp->w_lines[idx].wl_size = row - srow;
  1634.         ++idx;
  1635. #ifdef FEAT_FOLDING
  1636.         lnum += fold_count + 1;
  1637. #else
  1638.         ++lnum;
  1639. #endif
  1640.     }
  1641.     else
  1642.     {
  1643.         /* This line does not need updating, advance to the next one */
  1644.         row += wp->w_lines[idx++].wl_size;
  1645.         if (row > wp->w_height)    /* past end of screen */
  1646.         break;
  1647. #ifdef FEAT_FOLDING
  1648.         lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
  1649. #else
  1650.         ++lnum;
  1651. #endif
  1652. #ifdef FEAT_SYN_HL
  1653.         did_update = DID_NONE;
  1654. #endif
  1655.     }
  1656.  
  1657.     if (lnum > buf->b_ml.ml_line_count)
  1658.     {
  1659.         eof = TRUE;
  1660.         break;
  1661.     }
  1662.     }
  1663.     /*
  1664.      * End of loop over all window lines.
  1665.      */
  1666.  
  1667.  
  1668.     if (idx > wp->w_lines_valid)
  1669.     wp->w_lines_valid = idx;
  1670.  
  1671. #ifdef FEAT_SYN_HL
  1672.     /*
  1673.      * Let the syntax stuff know we stop parsing here.
  1674.      */
  1675.     if (syntax_last_parsed != 0 && syntax_present(buf))
  1676.     syntax_end_parsing(syntax_last_parsed + 1);
  1677. #endif
  1678.  
  1679.     /*
  1680.      * If we didn't hit the end of the file, and we didn't finish the last
  1681.      * line we were working on, then the line didn't fit.
  1682.      */
  1683.     wp->w_empty_rows = 0;
  1684. #ifdef FEAT_DIFF
  1685.     wp->w_filler_rows = 0;
  1686. #endif
  1687.     if (!eof && !didline)
  1688.     {
  1689.     if (lnum == wp->w_topline)
  1690.     {
  1691.         /*
  1692.          * Single line that does not fit!
  1693.          * Don't overwrite it, it can be edited.
  1694.          */
  1695.         wp->w_botline = lnum + 1;
  1696.     }
  1697. #ifdef FEAT_DIFF
  1698.     else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
  1699.     {
  1700.         /* Window ends in filler lines. */
  1701.         wp->w_botline = lnum;
  1702.         wp->w_filler_rows = wp->w_height - srow;
  1703.     }
  1704. #endif
  1705.     else if (dy_flags & DY_LASTLINE)    /* 'display' has "lastline" */
  1706.     {
  1707.         /*
  1708.          * Last line isn't finished: Display "@@@" at the end.
  1709.          */
  1710.         screen_fill(W_WINROW(wp) + wp->w_height - 1,
  1711.             W_WINROW(wp) + wp->w_height,
  1712.             (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
  1713.             '@', '@', hl_attr(HLF_AT));
  1714.         set_empty_rows(wp, srow);
  1715.         wp->w_botline = lnum;
  1716.     }
  1717.     else
  1718.     {
  1719.         win_draw_end(wp, '@', ' ', srow, wp->w_height, HLF_AT);
  1720.         wp->w_botline = lnum;
  1721.     }
  1722.     }
  1723.     else
  1724.     {
  1725. #ifdef FEAT_VERTSPLIT
  1726.     draw_vsep_win(wp, row);
  1727. #endif
  1728.     if (eof)        /* we hit the end of the file */
  1729.     {
  1730.         wp->w_botline = buf->b_ml.ml_line_count + 1;
  1731. #ifdef FEAT_DIFF
  1732.         j = diff_check_fill(wp, wp->w_botline);
  1733.         if (j > 0 && !wp->w_botfill)
  1734.         {
  1735.         /*
  1736.          * Display filler lines at the end of the file
  1737.          */
  1738.         if (char2cells(fill_diff) > 1)
  1739.             i = '-';
  1740.         else
  1741.             i = fill_diff;
  1742.         if (row + j > wp->w_height)
  1743.             j = wp->w_height - row;
  1744.         win_draw_end(wp, i, i, row, row + (int)j, HLF_DED);
  1745.         row += j;
  1746.         }
  1747. #endif
  1748.     }
  1749.     else if (dollar_vcol == 0)
  1750.         wp->w_botline = lnum;
  1751.  
  1752.     /* make sure the rest of the screen is blank */
  1753.     /* put '~'s on rows that aren't part of the file. */
  1754.     win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_AT);
  1755.     }
  1756.  
  1757.     /* Reset the type of redrawing required, the window has been updated. */
  1758.     wp->w_redr_type = 0;
  1759. #ifdef FEAT_DIFF
  1760.     wp->w_old_topfill = wp->w_topfill;
  1761.     wp->w_old_botfill = wp->w_botfill;
  1762. #endif
  1763.  
  1764.     if (dollar_vcol == 0)
  1765.     {
  1766.     /*
  1767.      * There is a trick with w_botline.  If we invalidate it on each
  1768.      * change that might modify it, this will cause a lot of expensive
  1769.      * calls to plines() in update_topline() each time.  Therefore the
  1770.      * value of w_botline is often approximated, and this value is used to
  1771.      * compute the value of w_topline.  If the value of w_botline was
  1772.      * wrong, check that the value of w_topline is correct (cursor is on
  1773.      * the visible part of the text).  If it's not, we need to redraw
  1774.      * again.  Mostly this just means scrolling up a few lines, so it
  1775.      * doesn't look too bad.  Only do this for the current window (where
  1776.      * changes are relevant).
  1777.      */
  1778.     wp->w_valid |= VALID_BOTLINE;
  1779.     if (wp == curwin && wp->w_botline != old_botline && !recursive)
  1780.     {
  1781.         recursive = TRUE;
  1782.         curwin->w_valid &= ~VALID_TOPLINE;
  1783.         update_topline();    /* may invalidate w_botline again */
  1784.         if (must_redraw != 0)
  1785.         {
  1786.         /* Don't update for changes in buffer again. */
  1787.         i = curbuf->b_mod_set;
  1788.         curbuf->b_mod_set = FALSE;
  1789.         win_update(curwin);
  1790.         must_redraw = 0;
  1791.         curbuf->b_mod_set = i;
  1792.         }
  1793.         recursive = FALSE;
  1794.     }
  1795.     }
  1796.  
  1797. #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
  1798.     /* restore got_int, unless CTRL-C was hit while redrawing */
  1799.     if (!got_int)
  1800.     got_int = save_got_int;
  1801. #endif
  1802. }
  1803.  
  1804. /*
  1805.  * Clear the rest of the window and mark the unused lines with "c1".  use "c2"
  1806.  * as the filler character.
  1807.  */
  1808.     static void
  1809. win_draw_end(wp, c1, c2, row, endrow, hl)
  1810.     win_T    *wp;
  1811.     int        c1;
  1812.     int        c2;
  1813.     int        row;
  1814.     int        endrow;
  1815.     enum hlf_value hl;
  1816. {
  1817. #if defined(FEAT_FOLDING) || defined(FEAT_CMDWIN)
  1818.     int        n = 0;
  1819. # define FDC_OFF n
  1820. #else
  1821. # define FDC_OFF 0
  1822. #endif
  1823.  
  1824. #ifdef FEAT_RIGHTLEFT
  1825.     if (wp->w_p_rl)
  1826.     {
  1827.     /* No check for cmdline window: should never be right-left. */
  1828. # ifdef FEAT_FOLDING
  1829.     n = wp->w_p_fdc;
  1830.  
  1831.     if (n > 0)
  1832.     {
  1833.         /* draw the fold column at the right */
  1834.         if (n > wp->w_width)
  1835.         n = wp->w_width;
  1836.         screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
  1837.             W_ENDCOL(wp) - n, (int)W_ENDCOL(wp),
  1838.             ' ', ' ', hl_attr(HLF_FC));
  1839.     }
  1840. # endif
  1841.     screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
  1842.         W_WINCOL(wp), W_ENDCOL(wp) - 1 - FDC_OFF,
  1843.         c2, c2, hl_attr(hl));
  1844.     screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
  1845.         W_ENDCOL(wp) - 1 - FDC_OFF, W_ENDCOL(wp) - FDC_OFF,
  1846.         c1, c2, hl_attr(hl));
  1847.     }
  1848.     else
  1849. #endif
  1850.     {
  1851. #ifdef FEAT_CMDWIN
  1852.     if (cmdwin_type != 0 && wp == curwin)
  1853.     {
  1854.         /* draw the cmdline character in the leftmost column */
  1855.         n = 1;
  1856.         if (n > wp->w_width)
  1857.         n = wp->w_width;
  1858.         screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
  1859.             W_WINCOL(wp), (int)W_WINCOL(wp) + n,
  1860.             cmdwin_type, ' ', hl_attr(HLF_AT));
  1861.     }
  1862. #endif
  1863. #ifdef FEAT_FOLDING
  1864.     if (wp->w_p_fdc > 0)
  1865.     {
  1866.         int        nn = n + wp->w_p_fdc;
  1867.  
  1868.         /* draw the fold column at the left */
  1869.         if (nn > W_WIDTH(wp))
  1870.         nn = W_WIDTH(wp);
  1871.         screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
  1872.             W_WINCOL(wp) + n, (int)W_WINCOL(wp) + nn,
  1873.             ' ', ' ', hl_attr(HLF_FC));
  1874.         n = nn;
  1875.     }
  1876. #endif
  1877.     screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
  1878.         W_WINCOL(wp) + FDC_OFF, (int)W_ENDCOL(wp),
  1879.         c1, c2, hl_attr(hl));
  1880.     }
  1881.     set_empty_rows(wp, row);
  1882. }
  1883.  
  1884. #ifdef FEAT_FOLDING
  1885. /*
  1886.  * Display one folded line.
  1887.  */
  1888.     static void
  1889. fold_line(wp, fold_count, foldinfo, lnum, row)
  1890.     win_T    *wp;
  1891.     long    fold_count;
  1892.     foldinfo_T    *foldinfo;
  1893.     linenr_T    lnum;
  1894.     int        row;
  1895. {
  1896.     char_u    buf[51];
  1897.     pos_T    *top, *bot;
  1898.     linenr_T    lnume = lnum + fold_count - 1;
  1899.     int        len;
  1900.     char_u    *p;
  1901.     char_u    *text = NULL;
  1902.     int        fdc;
  1903.     int        level;
  1904.     int        col;
  1905.     int        txtcol;
  1906.     int        off = (int)(current_ScreenLine - ScreenLines);
  1907.  
  1908.     /* Build the fold line:
  1909.      * 1. Add the cmdwin_type for the command-line window
  1910.      * 2. Add the 'foldcolumn'
  1911.      * 3. Add the 'number' column
  1912.      * 4. Compose the text
  1913.      * 5. Add the text
  1914.      * 6. set highlighting for the Visual area an other text
  1915.      */
  1916.     col = 0;
  1917.  
  1918.     /*
  1919.      * 1. Add the cmdwin_type for the command-line window
  1920.      * Ignores 'rightleft', this window is never right-left.
  1921.      */
  1922. #ifdef FEAT_CMDWIN
  1923.     if (cmdwin_type != 0 && wp == curwin)
  1924.     {
  1925.     ScreenLines[off] = cmdwin_type;
  1926.     ScreenAttrs[off] = hl_attr(HLF_AT);
  1927. #ifdef FEAT_MBYTE
  1928.     if (enc_utf8)
  1929.         ScreenLinesUC[off] = 0;
  1930. #endif
  1931.     ++col;
  1932.     }
  1933. #endif
  1934.  
  1935.     /*
  1936.      * 2. Add the 'foldcolumn'
  1937.      */
  1938.     fdc = wp->w_p_fdc;
  1939.     if (fdc > W_WIDTH(wp) - col)
  1940.     fdc = W_WIDTH(wp) - col;
  1941.     if (fdc > 0)
  1942.     {
  1943.     fill_foldcolumn(buf, wp, TRUE, lnum);
  1944. #ifdef FEAT_RIGHTLEFT
  1945.     if (wp->w_p_rl)
  1946.     {
  1947.         int        i;
  1948.  
  1949.         copy_text_attr(off + W_WIDTH(wp) - fdc - col, buf, fdc,
  1950.                                  hl_attr(HLF_FC));
  1951.         /* reverse the fold column */
  1952.         for (i = 0; i < fdc; ++i)
  1953.         ScreenLines[off + W_WIDTH(wp) - i - 1 - col] = buf[i];
  1954.     }
  1955.     else
  1956. #endif
  1957.         copy_text_attr(off + col, buf, fdc, hl_attr(HLF_FC));
  1958.     col += fdc;
  1959.     }
  1960.  
  1961. #ifdef FEAT_RIGHTLEFT
  1962. # define RL_MEMSET(p, v, l) vim_memset(ScreenAttrs + off + (wp->w_p_rl ? (W_WIDTH(wp) - (p) - (l)) : (p)), v, l)
  1963. #else
  1964. # define RL_MEMSET(p, v, l) vim_memset(ScreenAttrs + off + p, v, l)
  1965. #endif
  1966.  
  1967.     /* Set all attributes of the 'number' column and the text */
  1968.     RL_MEMSET(col, hl_attr(HLF_FL), (size_t)(W_WIDTH(wp) - col));
  1969.  
  1970.     /*
  1971.      * 3. Add the 'number' column
  1972.      */
  1973.     if (wp->w_p_nu)
  1974.     {
  1975.     len = W_WIDTH(wp) - col;
  1976.     if (len > 0)
  1977.     {
  1978.         if (len > 8)
  1979.         len = 8;
  1980.         sprintf((char *)buf, "%7ld ", (long)lnum);
  1981. #ifdef FEAT_RIGHTLEFT
  1982.         if (wp->w_p_rl)
  1983.         /* the line number isn't reversed */
  1984.         copy_text_attr(off + W_WIDTH(wp) - len - col, buf, len,
  1985.                                  hl_attr(HLF_FL));
  1986.         else
  1987. #endif
  1988.         copy_text_attr(off + col, buf, len, hl_attr(HLF_FL));
  1989.         col += len;
  1990.     }
  1991.     }
  1992.  
  1993.     /*
  1994.      * 4. Compose the folded-line string with 'foldtext', if set.
  1995.      */
  1996. #ifdef FEAT_EVAL
  1997.     if (*wp->w_p_fdt != NUL)
  1998.     {
  1999.     char_u    dashes[51];
  2000.     win_T    *save_curwin;
  2001.  
  2002.     /* Set "v:foldstart" and "v:foldend". */
  2003.     set_vim_var_nr(VV_FOLDSTART, lnum);
  2004.     set_vim_var_nr(VV_FOLDEND, lnume);
  2005.  
  2006.     /* Set "v:folddashes" to a string of "level" dashes. */
  2007.     /* Set "v:foldlevel" to "level". */
  2008.     level = foldinfo->fi_level;
  2009.     if (level > 50)
  2010.         level = 50;
  2011.     vim_memset(dashes, '-', (size_t)level);
  2012.     dashes[level] = NUL;
  2013.     set_vim_var_string(VV_FOLDDASHES, dashes, -1);
  2014.     set_vim_var_nr(VV_FOLDLEVEL, (long)level);
  2015.     save_curwin = curwin;
  2016.     curwin = wp;
  2017.     curbuf = wp->w_buffer;
  2018.  
  2019.     ++emsg_off;
  2020.     text = eval_to_string_safe(wp->w_p_fdt, NULL);
  2021.     --emsg_off;
  2022.  
  2023.     curwin = save_curwin;
  2024.     curbuf = curwin->w_buffer;
  2025.     set_vim_var_string(VV_FOLDDASHES, NULL, -1);
  2026.  
  2027.     if (text != NULL)
  2028.     {
  2029.         /* Replace unprintable characters, if there are any.  But
  2030.          * replace a TAB with a space. */
  2031.         for (p = text; *p != NUL; ++p)
  2032.         {
  2033. #ifdef FEAT_MBYTE
  2034.         if (has_mbyte && (len = (*mb_ptr2len_check)(p)) > 1)
  2035.             p += len - 1;
  2036.         else
  2037. #endif
  2038.             if (*p == TAB)
  2039.             *p = ' ';
  2040.             else if (ptr2cells(p) > 1)
  2041.             break;
  2042.         }
  2043.         if (*p != NUL)
  2044.         {
  2045.         p = transstr(text);
  2046.         vim_free(text);
  2047.         text = p;
  2048.         }
  2049.     }
  2050.     }
  2051.     if (text == NULL)
  2052. #endif
  2053.     {
  2054.     sprintf((char *)buf, _("+--%3ld lines folded "), fold_count);
  2055.     text = buf;
  2056.     }
  2057.  
  2058.     txtcol = col;    /* remember where text starts */
  2059.  
  2060.     /*
  2061.      * 5. move the text to current_ScreenLine.  Fill up with "fill_fold".
  2062.      *    Right-left text is put in columns 0 - number-col, normal text is put
  2063.      *    in columns number-col - window-width.
  2064.      */
  2065. #ifdef FEAT_MBYTE
  2066.     if (has_mbyte)
  2067.     {
  2068.     int    cells;
  2069.     int    u8c, u8c_c1, u8c_c2;
  2070.     int    idx;
  2071.  
  2072. # ifdef FEAT_RIGHTLEFT
  2073.     if (wp->w_p_rl)
  2074.         idx = off;
  2075.     else
  2076. # endif
  2077.         idx = off + col;
  2078.  
  2079.     /* Store multibyte characters in ScreenLines[] et al. correctly. */
  2080.     for (p = text; *p != NUL; )
  2081.     {
  2082.         cells = (*mb_ptr2cells)(p);
  2083.         if (col + cells > W_WIDTH(wp)
  2084. # ifdef FEAT_RIGHTLEFT
  2085.             - (wp->w_p_rl ? col : 0)
  2086. # endif
  2087.             )
  2088.         break;
  2089.         ScreenLines[idx] = *p;
  2090.         if (enc_utf8)
  2091.         {
  2092.         u8c = utfc_ptr2char(p, &u8c_c1, &u8c_c2);
  2093.         if (*p < 0x80 && u8c_c1 == 0 && u8c_c2 == 0)
  2094.             ScreenLinesUC[idx] = 0;
  2095.         else
  2096.         {
  2097.             ScreenLinesUC[idx] = u8c;
  2098.             ScreenLinesC1[idx] = u8c_c1;
  2099.             ScreenLinesC2[idx] = u8c_c2;
  2100.         }
  2101.         if (cells > 1)
  2102.             ScreenLines[idx + 1] = 0;
  2103.         }
  2104.         else if (cells > 1)        /* double-byte character */
  2105.         {
  2106.         if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
  2107.             ScreenLines2[idx] = p[1];
  2108.         else
  2109.             ScreenLines[idx + 1] = p[1];
  2110.         }
  2111.         col += cells;
  2112.         idx += cells;
  2113.         p += (*mb_ptr2len_check)(p);
  2114.     }
  2115.     }
  2116.     else
  2117. #endif
  2118.     {
  2119.     len = (int)STRLEN(text);
  2120.     if (len > W_WIDTH(wp) - col)
  2121.         len = W_WIDTH(wp) - col;
  2122.     if (len > 0)
  2123.     {
  2124. #ifdef FEAT_RIGHTLEFT
  2125.         if (wp->w_p_rl)
  2126.         STRNCPY(current_ScreenLine, text, len);
  2127.         else
  2128. #endif
  2129.         STRNCPY(current_ScreenLine + col, text, len);
  2130.         col += len;
  2131.     }
  2132.     }
  2133.  
  2134.     /* Fill the rest of the line with the fold filler */
  2135. #ifdef FEAT_RIGHTLEFT
  2136.     if (wp->w_p_rl)
  2137.     col -= txtcol;
  2138. #endif
  2139.     while (col < W_WIDTH(wp)
  2140. #ifdef FEAT_RIGHTLEFT
  2141.             - (wp->w_p_rl ? txtcol : 0)
  2142. #endif
  2143.         )
  2144.     {
  2145. #ifdef FEAT_MBYTE
  2146.     if (enc_utf8)
  2147.         ScreenLinesUC[off + col] = 0;
  2148. #endif
  2149.     ScreenLines[off + col++] = fill_fold;
  2150.     }
  2151.  
  2152.     if (text != buf)
  2153.     vim_free(text);
  2154.  
  2155.     /*
  2156.      * 6. set highlighting for the Visual area an other text.
  2157.      * If all folded lines are in the Visual area, highlight the line.
  2158.      */
  2159. #ifdef FEAT_VISUAL
  2160.     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
  2161.     {
  2162.     if (ltoreq(curwin->w_cursor, VIsual))
  2163.     {
  2164.         /* Visual is after curwin->w_cursor */
  2165.         top = &curwin->w_cursor;
  2166.         bot = &VIsual;
  2167.     }
  2168.     else
  2169.     {
  2170.         /* Visual is before curwin->w_cursor */
  2171.         top = &VIsual;
  2172.         bot = &curwin->w_cursor;
  2173.     }
  2174.     if (lnum >= top->lnum
  2175.         && lnume <= bot->lnum
  2176.         && (VIsual_mode != 'v'
  2177.             || ((lnum > top->lnum
  2178.                 || (lnum == top->lnum
  2179.                 && top->col == 0))
  2180.             && (lnume < bot->lnum
  2181.                 || (lnume == bot->lnum
  2182.                 && (bot->col - (*p_sel == 'e'))
  2183.         >= STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
  2184.     {
  2185.         if (VIsual_mode == Ctrl_V)
  2186.         {
  2187.         /* Visual block mode: highlight the chars part of the block */
  2188.         if (wp->w_old_cursor_fcol + txtcol < (colnr_T)W_WIDTH(wp))
  2189.         {
  2190.             if (wp->w_old_cursor_lcol + txtcol < (colnr_T)W_WIDTH(wp))
  2191.             len = wp->w_old_cursor_lcol;
  2192.             else
  2193.             len = W_WIDTH(wp) - txtcol;
  2194.             RL_MEMSET(wp->w_old_cursor_fcol + txtcol, hl_attr(HLF_V),
  2195.                        (size_t)(len - wp->w_old_cursor_fcol));
  2196.         }
  2197.         }
  2198.         else
  2199.         /* Set all attributes of the text */
  2200.         RL_MEMSET(txtcol, hl_attr(HLF_V),
  2201.                           (size_t)(W_WIDTH(wp) - txtcol));
  2202.     }
  2203.     }
  2204. #endif
  2205.  
  2206.  
  2207.     SCREEN_LINE(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp),
  2208.                              (int)W_WIDTH(wp), FALSE);
  2209.  
  2210.     /*
  2211.      * Update w_cline_height and w_cline_folded if the cursor line was
  2212.      * updated (saves a call to plines() later).
  2213.      */
  2214.     if (wp == curwin
  2215.         && lnum <= curwin->w_cursor.lnum
  2216.         && lnume >= curwin->w_cursor.lnum)
  2217.     {
  2218.     curwin->w_cline_row = row;
  2219.     curwin->w_cline_height = 1;
  2220.     curwin->w_cline_folded = TRUE;
  2221.     curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
  2222.     }
  2223. }
  2224.  
  2225. /*
  2226.  * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
  2227.  */
  2228.     static void
  2229. copy_text_attr(off, buf, len, attr)
  2230.     int        off;
  2231.     char_u    *buf;
  2232.     int        len;
  2233.     int        attr;
  2234. {
  2235.     mch_memmove(ScreenLines + off, buf, (size_t)len);
  2236. # ifdef FEAT_MBYTE
  2237.     if (enc_utf8)
  2238.     vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
  2239. # endif
  2240.     vim_memset(ScreenAttrs + off, attr, (size_t)len);
  2241. }
  2242.  
  2243. /*
  2244.  * Fill the foldcolumn at "p" for window "wp".
  2245.  */
  2246.     static void
  2247. fill_foldcolumn(p, wp, closed, lnum)
  2248.     char_u    *p;
  2249.     win_T    *wp;
  2250.     int        closed;        /* TRUE of FALSE */
  2251.     linenr_T    lnum;        /* current line number */
  2252. {
  2253.     int        i = 0;
  2254.     int        level;
  2255.     int        first_level;
  2256.  
  2257.     /* Init to all spaces. */
  2258.     copy_spaces(p, (size_t)wp->w_p_fdc);
  2259.  
  2260.     level = win_foldinfo.fi_level;
  2261.     if (level > 0)
  2262.     {
  2263.     /* If the column is too narrow, we start at the lowest level that
  2264.      * fits and use numbers to indicated the depth. */
  2265.     first_level = level - wp->w_p_fdc - closed + 2;
  2266.     if (first_level < 1)
  2267.         first_level = 1;
  2268.  
  2269.     for (i = 0; i + 1 < wp->w_p_fdc; ++i)
  2270.     {
  2271.         if (win_foldinfo.fi_lnum == lnum
  2272.                   && first_level + i >= win_foldinfo.fi_low_level)
  2273.         p[i] = '-';
  2274.         else if (first_level == 1)
  2275.         p[i] = '|';
  2276.         else if (first_level + i <= 9)
  2277.         p[i] = '0' + first_level + i;
  2278.         else
  2279.         p[i] = '>';
  2280.         if (first_level + i == level)
  2281.         break;
  2282.     }
  2283.     }
  2284.     if (closed)
  2285.     p[i] = '+';
  2286. }
  2287. #endif /* FEAT_FOLDING */
  2288.  
  2289. /*
  2290.  * Display line "lnum" of window 'wp' on the screen.
  2291.  * Start at row "startrow", stop when "endrow" is reached.
  2292.  * wp->w_virtcol needs to be valid.
  2293.  *
  2294.  * Return the number of last row the line occupies.
  2295.  */
  2296.     static int
  2297. win_line(wp, lnum, startrow, endrow)
  2298.     win_T    *wp;
  2299.     linenr_T    lnum;
  2300.     int        startrow;
  2301.     int        endrow;
  2302. {
  2303.     int        col;            /* visual column on screen */
  2304.     unsigned    off;            /* offset in ScreenLines/ScreenAttrs */
  2305.     int        c = 0;            /* init for GCC */
  2306.     long    vcol = 0;        /* virtual column (for tabs) */
  2307.     long    vcol_prev = -1;        /* "vcol" of previous character */
  2308.     char_u    *line;            /* current line */
  2309.     char_u    *ptr;            /* current position in "line" */
  2310.     int        row;            /* row in the window, excl w_winrow */
  2311.     int        screen_row;        /* row on the screen, incl w_winrow */
  2312.  
  2313.     char_u    extra[18];        /* "%ld" and 'fdc' must fit in here */
  2314.     int        n_extra = 0;        /* number of extra chars */
  2315.     char_u    *p_extra = NULL;    /* string of extra chars */
  2316.     int        c_extra = NUL;        /* extra chars, all the same */
  2317.     int        extra_attr = 0;        /* attributes when n_extra != 0 */
  2318.     static char_u *at_end_str = (char_u *)""; /* used for p_extra when
  2319.                        displaying lcs_eol at end-of-line */
  2320.     int        lcs_eol_one = lcs_eol;    /* lcs_eol until it's been used */
  2321.     int        lcs_prec_todo = lcs_prec;   /* lcs_prec until it's been used */
  2322.  
  2323.     /* saved "extra" items for when draw_state becomes WL_LINE (again) */
  2324.     int        saved_n_extra = 0;
  2325.     char_u    *saved_p_extra = NULL;
  2326.     int        saved_c_extra = 0;
  2327.     int        saved_char_attr = 0;
  2328.  
  2329.     int        n_attr = 0;        /* chars with special attr */
  2330.     int        saved_attr2 = 0;    /* char_attr saved for n_attr */
  2331.     int        n_attr3 = 0;        /* chars with overruling special attr */
  2332.     int        saved_attr3 = 0;    /* char_attr saved for n_attr3 */
  2333.  
  2334.     int        n_skip = 0;        /* nr of chars to skip for 'nowrap' */
  2335.  
  2336.     int        fromcol, tocol;        /* start/end of inverting */
  2337.     int        fromcol_prev = -2;    /* start of inverting after cursor */
  2338.     int        noinvcur = FALSE;    /* don't invert the cursor */
  2339. #ifdef FEAT_VISUAL
  2340.     pos_T    *top, *bot;
  2341. #endif
  2342.     pos_T    pos;
  2343.     long    v;
  2344.  
  2345.     int        char_attr = 0;        /* attributes for next character */
  2346.     int        area_highlighting = FALSE; /* Visual or incsearch highlighting
  2347.                           in this line */
  2348.     int        attr = 0;        /* attributes for area highlighting */
  2349.     int        area_attr = 0;        /* attributes desired by highlighting */
  2350.     int        search_attr = 0;    /* attributes desired by 'hlsearch' */
  2351. #ifdef FEAT_SYN_HL
  2352.     int        syntax_attr = 0;    /* attributes desired by syntax */
  2353.     int        has_syntax = FALSE;    /* this buffer has syntax highl. */
  2354.     int        save_did_emsg;
  2355. #endif
  2356.     int        extra_check;        /* has syntax or linebreak */
  2357. #ifdef FEAT_MBYTE
  2358.     int        multi_attr = 0;        /* attributes desired by multibyte */
  2359.     int        mb_l = 1;        /* multi-byte byte length */
  2360.     int        mb_c = 0;        /* decoded multi-byte character */
  2361.     int        mb_utf8 = FALSE;    /* screen char is UTF-8 char */
  2362.     int        u8c_c1 = 0;        /* first composing UTF-8 char */
  2363.     int        u8c_c2 = 0;        /* second composing UTF-8 char */
  2364. #endif
  2365. #ifdef FEAT_DIFF
  2366.     int        filler_lines;        /* nr of filler lines to be drawn */
  2367.     int        filler_todo;        /* nr of filler lines still to do + 1 */
  2368.     int        diff_attr = 0;        /* attributes for changed/added line */
  2369.     int        change_start = MAXCOL;    /* first col of changed area */
  2370.     int        change_end = -1;    /* last col of changed area */
  2371. #endif
  2372.     colnr_T    trailcol = MAXCOL;    /* start of trailing spaces */
  2373. #ifdef FEAT_LINEBREAK
  2374.     int        need_showbreak = FALSE;
  2375. #endif
  2376. #ifdef FEAT_SIGNS
  2377.     int_u    sign_typenr;        /* sign type (if signs are used) */
  2378. #endif
  2379. #if defined(FEAT_SIGNS) || (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS))
  2380. # define LINE_ATTR
  2381.     int        line_attr = 0;        /* atrribute for the whole line */
  2382. #endif
  2383. #ifdef FEAT_SEARCH_EXTRA
  2384.     match_T    *shl;            /* points to search_hl or match_hl */
  2385. #endif
  2386.  
  2387.     /* draw_state: items that are drawn in sequence: */
  2388. #define WL_START    0        /* nothing done yet */
  2389. #ifdef FEAT_CMDWIN
  2390. # define WL_CMDLINE    WL_START + 1    /* cmdline window column */
  2391. #else
  2392. # define WL_CMDLINE    WL_START
  2393. #endif
  2394. #ifdef FEAT_FOLDING
  2395. # define WL_FOLD    WL_CMDLINE + 1    /* 'foldcolumn' */
  2396. #else
  2397. # define WL_FOLD    WL_CMDLINE
  2398. #endif
  2399. #ifdef FEAT_SIGNS
  2400. # define WL_SIGN    WL_FOLD + 1    /* column for signs */
  2401. #else
  2402. # define WL_SIGN    WL_FOLD        /* column for signs */
  2403. #endif
  2404. #define WL_NR        WL_SIGN + 1    /* line number */
  2405. #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
  2406. # define WL_SBR        WL_NR + 1    /* 'showbreak' or 'diff' */
  2407. #else
  2408. # define WL_SBR        WL_NR
  2409. #endif
  2410. #define WL_LINE        WL_SBR + 1    /* text in the line */
  2411.     int        draw_state = WL_START;    /* what to draw next */
  2412.  
  2413.  
  2414.     if (startrow > endrow)        /* past the end already! */
  2415.     return startrow;
  2416.  
  2417.     row = startrow;
  2418.     screen_row = row + W_WINROW(wp);
  2419.  
  2420.     /*
  2421.      * To speed up the loop below, set extra_check when there is linebreak,
  2422.      * trailing white space and/or syntax processing to be done.
  2423.      */
  2424. #ifdef FEAT_LINEBREAK
  2425.     extra_check = wp->w_p_lbr;
  2426. #else
  2427.     extra_check = 0;
  2428. #endif
  2429. #ifdef FEAT_SYN_HL
  2430.     if (syntax_present(wp->w_buffer))
  2431.     {
  2432.     /* Prepare for syntax highlighting in this line.  When there is an
  2433.      * error, stop syntax highlighting. */
  2434.     save_did_emsg = did_emsg;
  2435.     did_emsg = FALSE;
  2436.     syntax_start(wp, lnum);
  2437.     if (did_emsg)
  2438.         syntax_clear(wp->w_buffer);
  2439.     else
  2440.     {
  2441.         did_emsg = save_did_emsg;
  2442.         has_syntax = TRUE;
  2443.         extra_check = TRUE;
  2444.     }
  2445.     }
  2446. #endif
  2447.  
  2448.     /*
  2449.      * handle visual active in this window
  2450.      */
  2451.     fromcol = -10;
  2452.     tocol = MAXCOL;
  2453. #ifdef FEAT_VISUAL
  2454.     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
  2455.     {
  2456.                     /* Visual is after curwin->w_cursor */
  2457.     if (ltoreq(curwin->w_cursor, VIsual))
  2458.     {
  2459.         top = &curwin->w_cursor;
  2460.         bot = &VIsual;
  2461.     }
  2462.     else                /* Visual is before curwin->w_cursor */
  2463.     {
  2464.         top = &VIsual;
  2465.         bot = &curwin->w_cursor;
  2466.     }
  2467.     if (VIsual_mode == Ctrl_V)    /* block mode */
  2468.     {
  2469.         if (lnum >= top->lnum && lnum <= bot->lnum)
  2470.         {
  2471.         fromcol = wp->w_old_cursor_fcol;
  2472.         tocol = wp->w_old_cursor_lcol;
  2473.         }
  2474.     }
  2475.     else                /* non-block mode */
  2476.     {
  2477.         if (lnum > top->lnum && lnum <= bot->lnum)
  2478.         fromcol = 0;
  2479.         else if (lnum == top->lnum)
  2480.         {
  2481.         if (VIsual_mode == 'V')    /* linewise */
  2482.             fromcol = 0;
  2483.         else
  2484.         {
  2485.             getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
  2486.             if (gchar_pos(top) == NUL)
  2487.             tocol = fromcol + 1;
  2488.         }
  2489.         }
  2490.         if (VIsual_mode != 'V' && lnum == bot->lnum)
  2491.         {
  2492.         if (*p_sel == 'e' && bot->col == 0)
  2493.         {
  2494.             fromcol = -10;
  2495.             tocol = MAXCOL;
  2496.         }
  2497.         else
  2498.         {
  2499.             pos = *bot;
  2500.             if (*p_sel == 'e')
  2501.             {
  2502.             --pos.col;
  2503. #ifdef FEAT_MBYTE
  2504.             if (has_mbyte)
  2505.             {
  2506.                 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
  2507.                 pos.col -= (*mb_head_off)(line, line + pos.col);
  2508.             }
  2509. #endif
  2510.             }
  2511.             getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
  2512.             ++tocol;
  2513.         }
  2514.         }
  2515.     }
  2516.  
  2517. #ifndef MSDOS
  2518.     /* Check if the character under the cursor should not be inverted */
  2519.     if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
  2520. # ifdef FEAT_GUI
  2521.         && !gui.in_use
  2522. # endif
  2523.         )
  2524.         noinvcur = TRUE;
  2525. #endif
  2526.  
  2527.     /* if inverting in this line set area_highlighting */
  2528.     if (fromcol >= 0)
  2529.     {
  2530.         area_highlighting = TRUE;
  2531.         attr = hl_attr(HLF_V);
  2532. #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
  2533.         if (clip_star.available && !clip_star.owned && clip_isautosel())
  2534.         attr = hl_attr(HLF_VNC);
  2535. #endif
  2536.     }
  2537.     }
  2538.  
  2539.     /*
  2540.      * handle 'insearch' and ":s///c" highlighting
  2541.      */
  2542.     else
  2543. #endif /* FEAT_VISUAL */
  2544.     if (highlight_match
  2545.         && wp == curwin
  2546.         && lnum >= curwin->w_cursor.lnum
  2547.         && lnum <= curwin->w_cursor.lnum + search_match_lines)
  2548.     {
  2549.     if (lnum == curwin->w_cursor.lnum)
  2550.         getvcol(curwin, &(curwin->w_cursor),
  2551.                          (colnr_T *)&fromcol, NULL, NULL);
  2552.     else
  2553.         fromcol = 0;
  2554.     if (lnum == curwin->w_cursor.lnum + search_match_lines)
  2555.     {
  2556.         pos.lnum = lnum;
  2557.         pos.col = search_match_endcol;
  2558.         getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
  2559.     }
  2560.     else
  2561.         tocol = MAXCOL;
  2562.     if (fromcol == tocol)        /* do at least one character */
  2563.         tocol = fromcol + 1;    /* happens when past end of line */
  2564.     area_highlighting = TRUE;
  2565.     attr = hl_attr(HLF_I);
  2566.     }
  2567.  
  2568. #ifdef FEAT_DIFF
  2569.     filler_lines = diff_check(wp, lnum);
  2570.     if (filler_lines < 0)
  2571.     {
  2572.     if (filler_lines == -1)
  2573.     {
  2574.         if (diff_find_change(wp, lnum, &change_start, &change_end))
  2575.         diff_attr = hl_attr(HLF_ADD);    /* added line */
  2576.         else if (change_start == 0)
  2577.         diff_attr = hl_attr(HLF_TXD);    /* changed text */
  2578.         else
  2579.         diff_attr = hl_attr(HLF_CHD);    /* changed line */
  2580.     }
  2581.     else
  2582.         diff_attr = hl_attr(HLF_ADD);    /* added line */
  2583.     filler_lines = 0;
  2584.     area_highlighting = TRUE;
  2585.     }
  2586.     if (lnum == wp->w_topline)
  2587.     filler_lines = wp->w_topfill;
  2588.     filler_todo = filler_lines;
  2589. #endif
  2590.  
  2591. #ifdef LINE_ATTR
  2592. # ifdef FEAT_SIGNS
  2593.     /* Draw a sign at the start of the line and/or highlight the line. */
  2594.     sign_typenr = buf_getsigntype(wp->w_buffer, lnum);
  2595.     if (sign_typenr != 0)
  2596.     line_attr = sign_get_attr(sign_typenr, TRUE);
  2597. # endif
  2598. # if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
  2599.     /* Highlight the current line in the quickfix window. */
  2600.     if (bt_quickfix(wp->w_buffer) && qf_current_entry() == lnum)
  2601.     line_attr = hl_attr(HLF_L);
  2602. # endif
  2603.     if (line_attr != 0)
  2604.     area_highlighting = TRUE;
  2605. #endif
  2606.  
  2607.     line = ml_get_buf(wp->w_buffer, lnum, FALSE);
  2608.     ptr = line;
  2609.  
  2610.     /* find start of trailing whitespace */
  2611.     if (wp->w_p_list && lcs_trail)
  2612.     {
  2613.     trailcol = (colnr_T)STRLEN(ptr);
  2614.     while (trailcol > (colnr_T)0 && vim_iswhite(ptr[trailcol - 1]))
  2615.         --trailcol;
  2616.     trailcol += (colnr_T) (ptr - line);
  2617.     extra_check = TRUE;
  2618.     }
  2619.  
  2620.     /*
  2621.      * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
  2622.      * first character to be displayed.
  2623.      */
  2624.     if (wp->w_p_wrap)
  2625.     v = wp->w_skipcol;
  2626.     else
  2627.     v = wp->w_leftcol;
  2628.     if (v > 0)
  2629.     {
  2630. #ifdef FEAT_MBYTE
  2631.     char_u    *prev_ptr = ptr;
  2632. #endif
  2633.     while (vcol < v && *ptr != NUL)
  2634.     {
  2635.         c = win_lbr_chartabsize(wp, ptr, (colnr_T)vcol, NULL);
  2636.         vcol += c;
  2637. #ifdef FEAT_MBYTE
  2638.         prev_ptr = ptr;
  2639.         if (has_mbyte)
  2640.         ptr += (*mb_ptr2len_check)(ptr);
  2641.         else
  2642. #endif
  2643.         ++ptr;
  2644.     }
  2645.     /* Handle a character that's not completely on the screen: Put ptr at
  2646.      * that character but skip the first few screen characters. */
  2647.     if (vcol > v)
  2648.     {
  2649.         vcol -= c;
  2650. #ifdef FEAT_MBYTE
  2651.         ptr = prev_ptr;
  2652. #else
  2653.         --ptr;
  2654. #endif
  2655.         n_skip = v - vcol;
  2656.     }
  2657.  
  2658.     /*
  2659.      * Adjust for when the inverted text is before the screen,
  2660.      * and when the start of the inverted text is before the screen.
  2661.      */
  2662.     if (tocol <= vcol)
  2663.         fromcol = 0;
  2664.     else if (fromcol >= 0 && fromcol < vcol)
  2665.         fromcol = vcol;
  2666.  
  2667. #ifdef FEAT_LINEBREAK
  2668.     /* When w_skipcol is non-zero, first line needs 'showbreak' */
  2669.     if (wp->w_p_wrap)
  2670.         need_showbreak = TRUE;
  2671. #endif
  2672.     }
  2673.  
  2674.     /*
  2675.      * Correct highlighting for cursor that can't be disabled.
  2676.      * Avoids having to check this for each character.
  2677.      */
  2678.     if (fromcol >= 0)
  2679.     {
  2680.     if (noinvcur)
  2681.     {
  2682.         if ((colnr_T)fromcol == wp->w_virtcol)
  2683.         {
  2684.         /* highlighting starts at cursor, let it start just after the
  2685.          * cursor */
  2686.         fromcol_prev = fromcol;
  2687.         fromcol = -1;
  2688.         }
  2689.         else if ((colnr_T)fromcol < wp->w_virtcol)
  2690.         /* restart highlighting after the cursor */
  2691.         fromcol_prev = wp->w_virtcol;
  2692.     }
  2693.     if (fromcol >= tocol)
  2694.         fromcol = -1;
  2695.     }
  2696.  
  2697. #ifdef FEAT_SEARCH_EXTRA
  2698.     /*
  2699.      * Handle highlighting the last used search pattern.
  2700.      * Do this for both search_hl and match_hl.
  2701.      */
  2702.     shl = &search_hl;
  2703.     for (;;)
  2704.     {
  2705.     shl->startp = NULL;
  2706.     shl->endp = NULL;
  2707.     shl->attr_cur = 0;
  2708.     if (shl->rm.regprog != NULL)
  2709.     {
  2710.         v = (long)(ptr - line);
  2711.         next_search_hl(wp, shl, lnum, (colnr_T)v);
  2712.  
  2713.         /* Need to get the line again, a multi-line regexp may have made it
  2714.          * invalid. */
  2715.         line = ml_get_buf(wp->w_buffer, lnum, FALSE);
  2716.         ptr = line + v;
  2717.  
  2718.         if (shl->lnum != 0 && shl->lnum <= lnum)
  2719.         {
  2720.         if (shl->lnum == lnum)
  2721.             shl->startp = line + shl->rm.startpos[0].col;
  2722.         else
  2723.             shl->startp = line;
  2724.         if (lnum == shl->lnum + shl->rm.endpos[0].lnum
  2725.                           - shl->rm.startpos[0].lnum)
  2726.             shl->endp = line + shl->rm.endpos[0].col;
  2727.         else
  2728.             shl->endp = line + MAXCOL;
  2729.         /* Highlight one character for an empty match. */
  2730.         if (shl->startp == shl->endp)
  2731.         {
  2732. #ifdef FEAT_MBYTE
  2733.             if (has_mbyte && *shl->endp != NUL)
  2734.             shl->endp += (*mb_ptr2len_check)(shl->endp);
  2735.             else
  2736. #endif
  2737.             ++shl->endp;
  2738.         }
  2739.         if (shl->startp < ptr)  /* match at leftcol */
  2740.         {
  2741.             shl->attr_cur = shl->attr;
  2742.             search_attr = shl->attr;
  2743.         }
  2744.         area_highlighting = TRUE;
  2745.         }
  2746.     }
  2747.     if (shl == &match_hl)
  2748.         break;
  2749.     shl = &match_hl;
  2750.     }
  2751. #endif
  2752.  
  2753.     off = (unsigned) (current_ScreenLine - ScreenLines);
  2754.     col = 0;
  2755. #ifdef FEAT_RIGHTLEFT
  2756.     if (wp->w_p_rl)
  2757.     {
  2758.     /* Rightleft window: process the text in the normal direction, but put
  2759.      * it in current_ScreenLine[] from right to left.  Start at the
  2760.      * rightmost column of the window. */
  2761.     col = W_WIDTH(wp) - 1;
  2762.     off += col;
  2763.     }
  2764. #endif
  2765.  
  2766.     /*
  2767.      * Repeat for the whole displayed line.
  2768.      */
  2769.     for (;;)
  2770.     {
  2771.     /* Skip this quickly when working on the text. */
  2772.     if (draw_state != WL_LINE)
  2773.     {
  2774. #ifdef FEAT_CMDWIN
  2775.         if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
  2776.         {
  2777.         draw_state = WL_CMDLINE;
  2778.         if (cmdwin_type != 0 && wp == curwin)
  2779.         {
  2780.             /* Draw the cmdline character. */
  2781.             *extra = cmdwin_type;
  2782.             n_extra = 1;
  2783.             p_extra = extra;
  2784.             c_extra = NUL;
  2785.             char_attr = hl_attr(HLF_AT);
  2786.         }
  2787.         }
  2788. #endif
  2789.  
  2790. #ifdef FEAT_FOLDING
  2791.         if (draw_state == WL_FOLD - 1 && n_extra == 0)
  2792.         {
  2793.         draw_state = WL_FOLD;
  2794.         if (wp->w_p_fdc > 0)
  2795.         {
  2796.             /* Draw the 'foldcolumn'. */
  2797.             fill_foldcolumn(extra, wp, FALSE, lnum);
  2798.             n_extra = wp->w_p_fdc;
  2799.             p_extra = extra;
  2800.             c_extra = NUL;
  2801.             char_attr = hl_attr(HLF_FC);
  2802.         }
  2803.         }
  2804. #endif
  2805.  
  2806. #ifdef FEAT_SIGNS
  2807.         if (draw_state == WL_SIGN - 1 && n_extra == 0)
  2808.         {
  2809.         draw_state = WL_SIGN;
  2810.         if (wp->w_buffer->b_signlist != NULL
  2811. # ifdef FEAT_DIFF
  2812.             && filler_todo <= 0
  2813. # endif
  2814.             )
  2815.         {
  2816.             /* Draw two bytes with the sign value or blank. */
  2817.             if (sign_typenr == 0 || row > startrow)
  2818.             {
  2819.             c_extra = ' ';
  2820.             char_attr = 0;
  2821.             }
  2822.             else
  2823.             {
  2824. # ifdef FEAT_SIGN_ICONS
  2825.             if (gui.in_use && sign_get_image(sign_typenr) != NULL)
  2826.             {
  2827.                 /* Use the image in this position. */
  2828.                 c_extra = SIGN_BYTE;
  2829.                 char_attr = sign_typenr;
  2830.             }
  2831.             else
  2832. # endif
  2833.             {
  2834.                 p_extra = sign_get_text(sign_typenr);
  2835.                 if (p_extra == NULL)
  2836.                 c_extra = ' ';
  2837.                 else
  2838.                 c_extra = NUL;
  2839.                 char_attr = sign_get_attr(sign_typenr, FALSE);
  2840.             }
  2841.             }
  2842.             n_extra = 2;
  2843.         }
  2844.         }
  2845. #endif
  2846.  
  2847.         if (draw_state == WL_NR - 1 && n_extra == 0)
  2848.         {
  2849.         draw_state = WL_NR;
  2850.         /* Display the line number.  After the first fill with blanks
  2851.          * when the 'n' flag isn't in 'cpo' */
  2852.         if (wp->w_p_nu
  2853.             && (row == startrow
  2854. #ifdef FEAT_DIFF
  2855.                 + filler_lines
  2856. #endif
  2857.                 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
  2858.         {
  2859.             /* Draw the line number (empty space after wrapping). */
  2860.             if (row == startrow
  2861. #ifdef FEAT_DIFF
  2862.                 + filler_lines
  2863. #endif
  2864.                 )
  2865.             {
  2866.             sprintf((char *)extra, "%7ld ", (long)lnum);
  2867.             if (wp->w_skipcol > 0)
  2868.                 for (p_extra = extra; *p_extra == ' '; ++p_extra)
  2869.                 *p_extra = '-';
  2870. #ifdef FEAT_RIGHTLEFT
  2871.             if (wp->w_p_rl)            /* reverse line numbers */
  2872.             {
  2873.                 char_u *c1, *c2, t;
  2874.  
  2875.                 for (c1 = extra, c2 = extra + STRLEN(extra) - 1;
  2876.                     c1 < c2; c1++, c2--)
  2877.                 {
  2878.                 t = *c1;
  2879.                 *c1 = *c2;
  2880.                 *c2 = t;
  2881.                 }
  2882.             }
  2883. #endif
  2884.             p_extra = extra;
  2885.             c_extra = NUL;
  2886.             }
  2887.             else
  2888.             c_extra = ' ';
  2889.             n_extra = 8;
  2890.             char_attr = hl_attr(HLF_N);
  2891.         }
  2892.         }
  2893.  
  2894. #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
  2895.         if (draw_state == WL_SBR - 1 && n_extra == 0)
  2896.         {
  2897.         draw_state = WL_SBR;
  2898. # ifdef FEAT_DIFF
  2899.         if (filler_todo > 0)
  2900.         {
  2901.             /* Draw "deleted" diff line(s). */
  2902.             if (char2cells(fill_diff) > 1)
  2903.             c_extra = '-';
  2904.             else
  2905.             c_extra = fill_diff;
  2906. #  ifdef FEAT_RIGHTLEFT
  2907.             if (wp->w_p_rl)
  2908.             n_extra = col + 1;
  2909.             else
  2910. #  endif
  2911.             n_extra = W_WIDTH(wp) - col;
  2912.             char_attr = hl_attr(HLF_DED);
  2913.         }
  2914. # endif
  2915. # ifdef FEAT_LINEBREAK
  2916.         if (*p_sbr != NUL && need_showbreak)
  2917.         {
  2918.             /* Draw 'showbreak' at the start of each broken line. */
  2919.             p_extra = p_sbr;
  2920.             c_extra = NUL;
  2921.             n_extra = (int)STRLEN(p_sbr);
  2922.             char_attr = hl_attr(HLF_AT);
  2923.             need_showbreak = FALSE;
  2924.             /* Correct end of highlighted area for 'showbreak',
  2925.              * required when 'linebreak' is also set. */
  2926.             if (tocol == vcol)
  2927.             tocol += n_extra;
  2928.         }
  2929. # endif
  2930.         }
  2931. #endif
  2932.  
  2933.         if (draw_state == WL_LINE - 1 && n_extra == 0)
  2934.         {
  2935.         draw_state = WL_LINE;
  2936.         if (saved_n_extra)
  2937.         {
  2938.             /* Continue item from end of wrapped line. */
  2939.             n_extra = saved_n_extra;
  2940.             c_extra = saved_c_extra;
  2941.             p_extra = saved_p_extra;
  2942.             char_attr = saved_char_attr;
  2943.         }
  2944.         else
  2945.             char_attr = 0;
  2946.         }
  2947.     }
  2948.  
  2949.     /* When still displaying '$' of change command, stop at cursor */
  2950.     if (dollar_vcol != 0 && wp == curwin && vcol >= (long)wp->w_virtcol
  2951. #ifdef FEAT_DIFF
  2952.                    && filler_todo <= 0
  2953. #endif
  2954.         )
  2955.     {
  2956.         SCREEN_LINE(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp),
  2957.                                   wp->w_p_rl);
  2958.         /* Pretend we have finished updating the window. */
  2959.         row = wp->w_height;
  2960.         break;
  2961.     }
  2962.  
  2963.     if (draw_state == WL_LINE && area_highlighting)
  2964.     {
  2965.         /* handle Visual or match highlighting in this line */
  2966.         if (vcol == fromcol
  2967. #ifdef FEAT_MBYTE
  2968.             || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
  2969.             && (*mb_ptr2cells)(ptr) > 1)
  2970. #endif
  2971.             || ((int)vcol_prev == fromcol_prev
  2972.             && vcol < tocol))
  2973.         area_attr = attr;        /* start highlighting */
  2974.         else if (area_attr != 0
  2975.             && (vcol == tocol
  2976.             || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
  2977. #ifdef LINE_ATTR
  2978.         area_attr = line_attr;        /* stop highlighting */
  2979.         else if (line_attr && ((fromcol == -10 && tocol == MAXCOL)
  2980.                      || (vcol < fromcol || vcol > tocol)))
  2981.         area_attr = line_attr;
  2982. #else
  2983.         area_attr = 0;            /* stop highlighting */
  2984. #endif
  2985.  
  2986. #ifdef FEAT_SEARCH_EXTRA
  2987.         if (!n_extra)
  2988.         {
  2989.         /*
  2990.          * Check for start/end of search pattern match.
  2991.          * After end, check for start/end of next match.
  2992.          * When another match, have to check for start again.
  2993.          * Watch out for matching an empty string!
  2994.          * Do this first for search_hl, then for match_hl, so that
  2995.          * ":match" overrules 'hlsearch'.
  2996.          */
  2997.         shl = &search_hl;
  2998.         for (;;)
  2999.         {
  3000.             for (;;)
  3001.             {
  3002.             if (shl->startp != NULL
  3003.                 && ptr >= shl->startp
  3004.                 && ptr < shl->endp)
  3005.             {
  3006.                 shl->attr_cur = shl->attr;
  3007.             }
  3008.             else if (ptr == shl->endp)
  3009.             {
  3010.                 shl->attr_cur = 0;
  3011.  
  3012.                 v = (long)(ptr - line);
  3013.                 next_search_hl(wp, shl, lnum, (colnr_T)v);
  3014.  
  3015.                 /* Need to get the line again, a multi-line regexp
  3016.                  * may have made it invalid. */
  3017.                 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
  3018.                 ptr = line + v;
  3019.  
  3020.                 if (shl->lnum == lnum)
  3021.                 {
  3022.                 shl->startp = line + shl->rm.startpos[0].col;
  3023.                 if (shl->rm.endpos[0].lnum == 0)
  3024.                     shl->endp = line + shl->rm.endpos[0].col;
  3025.                 else
  3026.                     shl->endp = line + MAXCOL;
  3027.  
  3028.                 /* for a non-null match, loop to check if the
  3029.                  * match starts at the current position */
  3030.                 if (shl->startp != shl->endp)
  3031.                     continue;
  3032.  
  3033.                 /* highlight empty match, try again after it */
  3034. #ifdef FEAT_MBYTE
  3035.                 if (has_mbyte)
  3036.                     shl->endp += (*mb_ptr2len_check)(shl->endp);
  3037.                 else
  3038. #endif
  3039.                     ++shl->endp;
  3040.                 }
  3041.             }
  3042.             break;
  3043.             }
  3044.             if (shl == &match_hl)
  3045.             break;
  3046.             shl = &match_hl;
  3047.         }
  3048.         /* ":match" highlighting overrules 'hlsearch' */
  3049.         if (match_hl.attr_cur != 0)
  3050.             search_attr = match_hl.attr_cur;
  3051.         else
  3052.             search_attr = search_hl.attr_cur;
  3053.         }
  3054. #endif
  3055.  
  3056.         if (area_attr != 0)
  3057.         char_attr = area_attr;
  3058. #ifdef FEAT_SYN_HL
  3059.         else if (search_attr == 0 && has_syntax)
  3060.         char_attr = syntax_attr;
  3061. #endif
  3062.         else
  3063.         char_attr = search_attr;
  3064.  
  3065. #ifdef FEAT_DIFF
  3066.         if (diff_attr != 0 && n_extra == 0)
  3067.         {
  3068.         if (diff_attr == hl_attr(HLF_CHD) && ptr - line >= change_start)
  3069.             diff_attr = hl_attr(HLF_TXD);    /* changed text */
  3070.         if (diff_attr == hl_attr(HLF_TXD) && ptr - line > change_end)
  3071.             diff_attr = hl_attr(HLF_CHD);    /* changed line */
  3072.         if (attr == 0 || area_attr != attr)
  3073.             area_attr = diff_attr;
  3074.         if (attr == 0 || char_attr != attr)
  3075.             char_attr = diff_attr;
  3076.         }
  3077. #endif
  3078.     }
  3079.  
  3080.     /*
  3081.      * Get the next character to put on the screen.
  3082.      */
  3083.     /*
  3084.      * The 'extra' array contains the extra stuff that is inserted to
  3085.      * represent special characters (non-printable stuff).  When all
  3086.      * characters are the same, c_extra is used.
  3087.      * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
  3088.      */
  3089.     if (n_extra > 0)
  3090.     {
  3091.         if (c_extra != NUL)
  3092.         {
  3093.         c = c_extra;
  3094. #ifdef FEAT_MBYTE
  3095.         mb_c = c;    /* doesn't handle multi-byte! */
  3096. #endif
  3097.         }
  3098.         else
  3099.         {
  3100.         c = *p_extra;
  3101. #ifdef FEAT_MBYTE
  3102.         if (has_mbyte)
  3103.         {
  3104.             mb_c = c;
  3105.             if (enc_utf8)
  3106.             {
  3107.             /* If the UTF-8 character is more than one byte:
  3108.              * Decode it into "mb_c". */
  3109.             mb_l = (*mb_ptr2len_check)(p_extra);
  3110.             mb_utf8 = FALSE;
  3111.             if (mb_l > n_extra)
  3112.                 mb_l = 1;
  3113.             else if (mb_l > 1)
  3114.             {
  3115.                 mb_c = utfc_ptr2char(p_extra, &u8c_c1, &u8c_c2);
  3116.                 mb_utf8 = TRUE;
  3117.             }
  3118.             }
  3119.             else
  3120.             {
  3121.             /* if this is a DBCS character, put it in "mb_c" */
  3122.             mb_l = MB_BYTE2LEN(c);
  3123.             if (mb_l >= n_extra)
  3124.                 mb_l = 1;
  3125.             else if (mb_l > 1)
  3126.                 mb_c = (c << 8) + p_extra[1];
  3127.             }
  3128.             /* If a double-width char doesn't fit display a '>' in the
  3129.              * last column. */
  3130.             if (
  3131. # ifdef FEAT_RIGHTLEFT
  3132.                 wp->w_p_rl ? (col <= 0) :
  3133. # endif
  3134.                     (col >= W_WIDTH(wp) - 1)
  3135.                 && (*mb_char2cells)(mb_c) == 2)
  3136.             {
  3137.             c = '>';
  3138.             mb_c = c;
  3139.             mb_l = 1;
  3140.             mb_utf8 = FALSE;
  3141.             multi_attr = hl_attr(HLF_AT);
  3142.             /* put the pointer back to output the double-width
  3143.              * character at the start of the next line. */
  3144.             ++n_extra;
  3145.             --p_extra;
  3146.             }
  3147.             else
  3148.             {
  3149.             n_extra -= mb_l - 1;
  3150.             p_extra += mb_l - 1;
  3151.             }
  3152.         }
  3153. #endif
  3154.         ++p_extra;
  3155.         }
  3156.         --n_extra;
  3157.     }
  3158.     else
  3159.     {
  3160.         /*
  3161.          * Get a character from the line itself.
  3162.          */
  3163.         c = *ptr;
  3164. #ifdef FEAT_MBYTE
  3165.         if (has_mbyte)
  3166.         {
  3167.         mb_c = c;
  3168.         if (enc_utf8)
  3169.         {
  3170.             /* If the UTF-8 character is more than one byte: Decode it
  3171.              * into "mb_c". */
  3172.             mb_l = (*mb_ptr2len_check)(ptr);
  3173.             mb_utf8 = FALSE;
  3174.             if (mb_l > 1)
  3175.             {
  3176.             mb_c = utfc_ptr2char(ptr, &u8c_c1, &u8c_c2);
  3177.             /* Overlong encoded ASCII or ASCII with composing char
  3178.              * is displayed normally, except a NUL. */
  3179.             if (mb_c < 0x80)
  3180.                 c = mb_c;
  3181.             mb_utf8 = TRUE;
  3182.             }
  3183.             if ((mb_l == 1 && c >= 0x80)
  3184.                 || (mb_l >= 1 && mb_c == 0)
  3185.                 || (mb_l > 1 && !vim_isprintc(mb_c)))
  3186.             {
  3187.             /*
  3188.              * Illegal UTF-8 byte: display as <xx>.
  3189.              */
  3190.             transchar_hex(extra, mb_c);
  3191.             p_extra = extra;
  3192.             c = *p_extra++;
  3193.             mb_c = c;
  3194.             mb_utf8 = FALSE;
  3195.             n_extra = (int)STRLEN(p_extra);
  3196.             c_extra = NUL;
  3197.             if (area_attr == 0 && search_attr == 0)
  3198.             {
  3199.                 n_attr = n_extra + 1;
  3200.                 extra_attr = hl_attr(HLF_8);
  3201.                 saved_attr2 = char_attr; /* save current attr */
  3202.             }
  3203.             }
  3204.             else if (mb_l == 0)  /* at the NUL at end-of-line */
  3205.             mb_l = 1;
  3206.         }
  3207.         else    /* enc_dbcs */
  3208.         {
  3209.             mb_l = MB_BYTE2LEN(c);
  3210.             if (mb_l == 0)  /* at the NUL at end-of-line */
  3211.             mb_l = 1;
  3212.             else if (mb_l > 1)
  3213.             {
  3214.             if (ptr[1] != NUL)
  3215.                 mb_c = (c << 8) + ptr[1];
  3216.             else
  3217.             {
  3218.                 /* head byte at end of line */
  3219.                 mb_l = 1;
  3220.                 transchar_nonprint(extra, c);
  3221.                 p_extra = extra;
  3222.                 n_extra = (int)STRLEN(extra) - 1;
  3223.                 c_extra = NUL;
  3224.                 c = *p_extra++;
  3225.                 if (area_attr == 0 && search_attr == 0)
  3226.                 {
  3227.                 n_attr = n_extra + 1;
  3228.                 extra_attr = hl_attr(HLF_8);
  3229.                 saved_attr2 = char_attr; /* save current attr */
  3230.                 }
  3231.                 mb_c = c;
  3232.             }
  3233.             }
  3234.         }
  3235.         /* If a double-width char doesn't fit display a '>' in the
  3236.          * last column; the character is displayed at the start of the
  3237.          * next line. */
  3238.         if ((
  3239. # ifdef FEAT_RIGHTLEFT
  3240.                 wp->w_p_rl ? (col <= 0) :
  3241. # endif
  3242.                 (col >= W_WIDTH(wp) - 1))
  3243.             && (*mb_char2cells)(mb_c) == 2)
  3244.         {
  3245.             c = '>';
  3246.             mb_c = c;
  3247.             mb_utf8 = FALSE;
  3248.             mb_l = 1;
  3249.             multi_attr = hl_attr(HLF_AT);
  3250.             /* Put pointer back so that the character will be
  3251.              * displayed at the start of the next line. */
  3252.             --ptr;
  3253.         }
  3254.         else if (*ptr != NUL)
  3255.             ptr += mb_l - 1;
  3256.  
  3257.         /* If a double-width char doesn't fit at the left side display
  3258.          * a '<' in the first column. */
  3259.         if (n_skip > 0 && mb_l > 1)
  3260.         {
  3261.             extra[0] = '<';
  3262.             p_extra = extra;
  3263.             n_extra = 1;
  3264.             c_extra = NUL;
  3265.             c = ' ';
  3266.             if (area_attr == 0 && search_attr == 0)
  3267.             {
  3268.             n_attr = n_extra + 1;
  3269.             extra_attr = hl_attr(HLF_AT);
  3270.             saved_attr2 = char_attr; /* save current attr */
  3271.             }
  3272.             mb_c = c;
  3273.             mb_utf8 = FALSE;
  3274.             mb_l = 1;
  3275.         }
  3276.  
  3277.         }
  3278. #endif
  3279.         ++ptr;
  3280.  
  3281.         if (extra_check)
  3282.         {
  3283. #ifdef FEAT_SYN_HL
  3284.         if (has_syntax)
  3285.         {
  3286.             /* Get the syntax attribute for the character.  If there
  3287.              * is an error, disable syntax highlighting. */
  3288.             save_did_emsg = did_emsg;
  3289.             did_emsg = FALSE;
  3290.  
  3291.             v = (long)(ptr - line);
  3292.             syntax_attr = get_syntax_attr((colnr_T)v - 1);
  3293.  
  3294.             if (did_emsg)
  3295.             syntax_clear(wp->w_buffer);
  3296.             else
  3297.             did_emsg = save_did_emsg;
  3298.  
  3299.             /* Need to get the line again, a multi-line regexp may
  3300.              * have made it invalid. */
  3301.             line = ml_get_buf(wp->w_buffer, lnum, FALSE);
  3302.             ptr = line + v;
  3303.  
  3304.             if (area_attr == 0 && search_attr == 0)
  3305.             char_attr = syntax_attr;
  3306.         }
  3307. #endif
  3308. #ifdef FEAT_LINEBREAK
  3309.         /*
  3310.          * Found last space before word: check for line break
  3311.          */
  3312.         if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
  3313.                               && !wp->w_p_list)
  3314.         {
  3315.             n_extra = win_lbr_chartabsize(wp, ptr - (
  3316. # ifdef FEAT_MBYTE
  3317.                 has_mbyte ? mb_l :
  3318. # endif
  3319.                 1), (colnr_T)vcol, NULL) - 1;
  3320.             c_extra = ' ';
  3321.             if (vim_iswhite(c))
  3322.             c = ' ';
  3323.         }
  3324. #endif
  3325.  
  3326.         if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
  3327.         {
  3328.             c = lcs_trail;
  3329.             if (area_attr == 0 && search_attr == 0)
  3330.             {
  3331.             n_attr = 1;
  3332.             extra_attr = hl_attr(HLF_8);
  3333.             saved_attr2 = char_attr; /* save current attr */
  3334.             }
  3335.         }
  3336.         }
  3337.  
  3338.         /*
  3339.          * Handling of non-printable characters.
  3340.          */
  3341.         if (!(chartab[c] & CT_PRINT_CHAR))
  3342.         {
  3343.         /*
  3344.          * when getting a character from the file, we may have to
  3345.          * turn it into something else on the way to putting it
  3346.          * into "ScreenLines".
  3347.          */
  3348.         if (c == TAB && (!wp->w_p_list || lcs_tab1))
  3349.         {
  3350.             /* tab amount depends on current column */
  3351.             n_extra = (int)wp->w_buffer->b_p_ts
  3352.                    - vcol % (int)wp->w_buffer->b_p_ts - 1;
  3353.             if (wp->w_p_list)
  3354.             {
  3355.             c = lcs_tab1;
  3356.             c_extra = lcs_tab2;
  3357.             n_attr = n_extra + 1;
  3358.             extra_attr = hl_attr(HLF_8);
  3359.             saved_attr2 = char_attr; /* save current attr */
  3360.             }
  3361.             else
  3362.             {
  3363.             c_extra = ' ';
  3364.             c = ' ';
  3365.             }
  3366. #ifdef FEAT_MBYTE
  3367.             mb_utf8 = FALSE;    /* don't draw as UTF-8 */
  3368. #endif
  3369.         }
  3370.         else if (c == NUL && wp->w_p_list && lcs_eol_one != NUL)
  3371.         {
  3372. #if defined(FEAT_DIFF) || defined(LINE_ATTR)
  3373.             /* For a diff line the highlighting continues after the
  3374.              * "$". */
  3375.             if (
  3376. # ifdef FEAT_DIFF
  3377.                 diff_attr == 0
  3378. #  ifdef LINE_ATTR
  3379.                 &&
  3380. #  endif
  3381. # endif
  3382. # ifdef LINE_ATTR
  3383.                 line_attr == 0
  3384. # endif
  3385.                )
  3386. #endif
  3387.             {
  3388. #ifdef FEAT_VIRTUALEDIT
  3389.             /* In virtualedit, visual selections may extend
  3390.              * beyond end of line. */
  3391.             if (area_highlighting && virtual_active()
  3392.                 && tocol != MAXCOL && vcol < tocol)
  3393.                 n_extra = 0;
  3394.             else
  3395. #endif
  3396.             {
  3397.                 p_extra = at_end_str;
  3398.                 n_extra = 1;
  3399.                 c_extra = NUL;
  3400.             }
  3401.             }
  3402.             c = lcs_eol;
  3403.             lcs_eol_one = NUL;
  3404.             --ptr;        /* put it back at the NUL */
  3405.             if (area_attr == 0 && search_attr == 0)
  3406.             {
  3407.             extra_attr = hl_attr(HLF_AT);
  3408.             n_attr = 1;
  3409.             }
  3410. #ifdef FEAT_MBYTE
  3411.             mb_utf8 = FALSE;    /* don't draw as UTF-8 */
  3412. #endif
  3413.         }
  3414.         else if (c != NUL)
  3415.         {
  3416.             p_extra = transchar(c);
  3417.             n_extra = byte2cells(c) - 1;
  3418.             c_extra = NUL;
  3419.             c = *p_extra++;
  3420.             if (area_attr == 0 && search_attr == 0)
  3421.             {
  3422.             n_attr = n_extra + 1;
  3423.             extra_attr = hl_attr(HLF_8);
  3424.             saved_attr2 = char_attr; /* save current attr */
  3425.             }
  3426. #ifdef FEAT_MBYTE
  3427.             mb_utf8 = FALSE;    /* don't draw as UTF-8 */
  3428. #endif
  3429.         }
  3430. #ifdef FEAT_VIRTUALEDIT
  3431.         else if (VIsual_active
  3432.              && (VIsual_mode == Ctrl_V
  3433.                  || VIsual_mode == 'v')
  3434.              && virtual_active()
  3435.              && tocol != MAXCOL
  3436.              && vcol < tocol
  3437.              && (
  3438. # ifdef FEAT_RIGHTLEFT
  3439.                 wp->w_p_rl ? (col >= 0) :
  3440. # endif
  3441.                 (col < W_WIDTH(wp))))
  3442.         {
  3443.             c = ' ';
  3444.             --ptr;        /* put it back at the NUL */
  3445.         }
  3446. #endif
  3447. #if defined(FEAT_DIFF) || defined(LINE_ATTR)
  3448.         else if ((
  3449. # ifdef FEAT_DIFF
  3450.                 diff_attr != 0
  3451. #  ifdef LINE_ATTR
  3452.                 ||
  3453. #  endif
  3454. # endif
  3455. # ifdef LINE_ATTR
  3456.                 line_attr != 0
  3457. # endif
  3458.             ) && col < W_WIDTH(wp))
  3459.         {
  3460.             /* Highlight until the right side of the window */
  3461.             c = ' ';
  3462.             --ptr;        /* put it back at the NUL */
  3463. # ifdef FEAT_DIFF
  3464.             if (diff_attr == hl_attr(HLF_TXD))
  3465.             {
  3466.             diff_attr = hl_attr(HLF_CHD);
  3467.             if (attr == 0 || char_attr != attr)
  3468.                 char_attr = diff_attr;
  3469.             }
  3470. # endif
  3471.         }
  3472. #endif
  3473.         }
  3474.     }
  3475.  
  3476.     /* Don't override visual selection highlighting. */
  3477.     if (n_attr > 0
  3478.         && (area_attr == 0 || char_attr != area_attr)
  3479.         && (search_attr == 0 || char_attr != search_attr))
  3480.         char_attr = extra_attr;
  3481.  
  3482.     /*
  3483.      * Handle the case where we are in column 0 but not on the first
  3484.      * character of the line and the user wants us to show us a
  3485.      * special character (via 'listchars' option "precedes:<char>".
  3486.      */
  3487.     if (lcs_prec_todo != NUL
  3488.         && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
  3489. #ifdef FEAT_DIFF
  3490.         && filler_todo <= 0
  3491. #endif
  3492.         && draw_state > WL_NR
  3493.         && c != NUL)
  3494.     {
  3495.         c = lcs_prec;
  3496.         lcs_prec_todo = NUL;
  3497. #ifdef FEAT_MBYTE
  3498.         mb_utf8 = FALSE;    /* don't draw as UTF-8 */
  3499. #endif
  3500.         if ((area_attr == 0 || char_attr != area_attr)
  3501.             && (search_attr == 0 || char_attr != search_attr))
  3502.         {
  3503.         saved_attr3 = char_attr; /* save current attr */
  3504.         char_attr = hl_attr(HLF_AT); /* later copied to char_attr */
  3505.         n_attr3 = 1;
  3506.         }
  3507.     }
  3508.  
  3509.     /*
  3510.      * At end of the text line.
  3511.      */
  3512.     if (c == NUL)
  3513.     {
  3514.         /* invert at least one char, used for Visual and empty line or
  3515.          * highlight match at end of line. If it's beyond the last
  3516.          * char on the screen, just overwrite that one (tricky!)  Not
  3517.          * needed when a '$' was displayed for 'list'. */
  3518.         if (lcs_eol == lcs_eol_one
  3519.             && ((area_attr != 0 && vcol == fromcol)
  3520. #ifdef FEAT_SEARCH_EXTRA
  3521.             /* highlight 'hlsearch' match at end of line */
  3522.             || ptr - 1 == search_hl.startp
  3523.             || ptr - 1 == match_hl.startp
  3524. #endif
  3525.                ))
  3526.         {
  3527. #ifdef FEAT_RIGHTLEFT
  3528.         if (wp->w_p_rl)
  3529.         {
  3530.             if (col < 0)
  3531.             {
  3532.             ++off;
  3533.             ++col;
  3534.             }
  3535.         }
  3536.         else
  3537. #endif
  3538.         {
  3539.             if (col >= W_WIDTH(wp))
  3540.             {
  3541.             --off;
  3542.             --col;
  3543.             }
  3544.         }
  3545.         ScreenLines[off] = ' ';
  3546. #ifdef FEAT_MBYTE
  3547.         if (enc_utf8)
  3548.             ScreenLinesUC[off] = 0;
  3549. #endif
  3550. #ifdef FEAT_SEARCH_EXTRA
  3551.         if (area_attr == 0)
  3552.         {
  3553.             if (ptr - 1 == match_hl.startp)
  3554.             char_attr = match_hl.attr;
  3555.             else
  3556.             char_attr = search_hl.attr;
  3557.         }
  3558. #endif
  3559.         ScreenAttrs[off] = char_attr;
  3560. #ifdef FEAT_RIGHTLEFT
  3561.         if (wp->w_p_rl)
  3562.             --col;
  3563.         else
  3564. #endif
  3565.             ++col;
  3566.         }
  3567.  
  3568.         SCREEN_LINE(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp),
  3569.                                   wp->w_p_rl);
  3570.         row++;
  3571.  
  3572.         /*
  3573.          * Update w_cline_height and w_cline_folded if the cursor line was
  3574.          * updated (saves a call to plines() later).
  3575.          */
  3576.         if (wp == curwin && lnum == curwin->w_cursor.lnum)
  3577.         {
  3578.         curwin->w_cline_row = startrow;
  3579.         curwin->w_cline_height = row - startrow;
  3580. #ifdef FEAT_FOLDING
  3581.         curwin->w_cline_folded = FALSE;
  3582. #endif
  3583.         curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
  3584.         }
  3585.  
  3586.         break;
  3587.     }
  3588.  
  3589.     /* line continues beyond line end */
  3590.     if (lcs_ext
  3591.         && !wp->w_p_wrap
  3592. #ifdef FEAT_DIFF
  3593.         && filler_todo <= 0
  3594. #endif
  3595.         && (
  3596. #ifdef FEAT_RIGHTLEFT
  3597.             wp->w_p_rl ? col == 0 :
  3598. #endif
  3599.             col == W_WIDTH(wp) - 1)
  3600.         && (*ptr != NUL
  3601.             || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
  3602.             || (n_extra && (c_extra != NUL || *p_extra != NUL))))
  3603.     {
  3604.         c = lcs_ext;
  3605.         char_attr = hl_attr(HLF_AT);
  3606.     }
  3607.  
  3608.     /*
  3609.      * Store character to be displayed.
  3610.      * Skip characters that are left of the screen for 'nowrap'.
  3611.      */
  3612.     vcol_prev = vcol;
  3613.     if (draw_state < WL_LINE || n_skip <= 0)
  3614.     {
  3615.         /*
  3616.          * Store the character.
  3617.          */
  3618. #if defined(FEAT_RIGHTLEFT) && defined(FEAT_MBYTE)
  3619.         if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
  3620.         {
  3621.         /* A double-wide character is: put first halve in left cell. */
  3622.         --off;
  3623.         --col;
  3624.         }
  3625. #endif
  3626.         ScreenLines[off] = c;
  3627. #ifdef FEAT_MBYTE
  3628.         if (enc_dbcs == DBCS_JPNU)
  3629.         ScreenLines2[off] = mb_c & 0xff;
  3630.         else if (enc_utf8)
  3631.         {
  3632.         if (mb_utf8)
  3633.         {
  3634.             ScreenLinesUC[off] = mb_c;
  3635.             ScreenLinesC1[off] = u8c_c1;
  3636.             ScreenLinesC2[off] = u8c_c2;
  3637.         }
  3638.         else
  3639.             ScreenLinesUC[off] = 0;
  3640.         }
  3641.         if (multi_attr)
  3642.         {
  3643.         ScreenAttrs[off] = multi_attr;
  3644.         multi_attr = 0;
  3645.         }
  3646.         else
  3647. #endif
  3648.         ScreenAttrs[off] = char_attr;
  3649.  
  3650. #ifdef FEAT_MBYTE
  3651.         if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
  3652.         {
  3653.         /* Need to fill two screen columns. */
  3654.         ++off;
  3655.         ++col;
  3656.         if (enc_utf8)
  3657.             /* UTF-8: Put a 0 in the second screen char. */
  3658.             ScreenLines[off] = 0;
  3659.         else
  3660.             /* DBCS: Put second byte in the second screen char. */
  3661.             ScreenLines[off] = mb_c & 0xff;
  3662.         ++vcol;
  3663.         /* When "tocol" is halfway a character, set it to the end of
  3664.          * the character, otherwise highlighting won't stop. */
  3665.         if (tocol == vcol)
  3666.             ++tocol;
  3667. #ifdef FEAT_RIGHTLEFT
  3668.         if (wp->w_p_rl)
  3669.         {
  3670.             /* now it's time to backup one cell */
  3671.             --off;
  3672.             --col;
  3673.         }
  3674. #endif
  3675.         }
  3676. #endif
  3677. #ifdef FEAT_RIGHTLEFT
  3678.         if (wp->w_p_rl)
  3679.         {
  3680.         --off;
  3681.         --col;
  3682.         }
  3683.         else
  3684. #endif
  3685.         {
  3686.         ++off;
  3687.         ++col;
  3688.         }
  3689.     }
  3690.     else
  3691.         --n_skip;
  3692.  
  3693.     /* Only advance the "vcol" when after the 'number' column. */
  3694.     if (draw_state >= WL_SBR
  3695. #ifdef FEAT_DIFF
  3696.         && filler_todo <= 0
  3697. #endif
  3698.         )
  3699.         ++vcol;
  3700.  
  3701.     /* restore attributes after "predeces" in 'listchars' */
  3702.     if (n_attr3 && --n_attr3 == 0)
  3703.         char_attr = saved_attr3;
  3704.  
  3705.     /* restore attributes after last 'listchars' or 'number' char */
  3706.     if (n_attr && --n_attr == 0)
  3707.         char_attr = saved_attr2;
  3708.  
  3709.     /*
  3710.      * At end of screen line and there is more to come: Display the line
  3711.      * so far.  If there is no more to display it is catched above.
  3712.      */
  3713.     if ((
  3714. #ifdef FEAT_RIGHTLEFT
  3715.         wp->w_p_rl ? (col < 0) :
  3716. #endif
  3717.                     (col >= W_WIDTH(wp)))
  3718.         && (*ptr != NUL
  3719. #ifdef FEAT_DIFF
  3720.             || filler_todo > 0
  3721. #endif
  3722.             || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
  3723.             || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
  3724.         )
  3725.     {
  3726.         SCREEN_LINE(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp),
  3727.                                   wp->w_p_rl);
  3728.         ++row;
  3729.         ++screen_row;
  3730.  
  3731.         /* When not wrapping and finished diff lines, break here. */
  3732.         if (!wp->w_p_wrap
  3733. #ifdef FEAT_DIFF
  3734.             && filler_todo <= 0
  3735. #endif
  3736.             )
  3737.         break;
  3738.  
  3739.         /* When the window is too narrow draw all "@" lines. */
  3740.         if (draw_state != WL_LINE
  3741. #ifdef FEAT_DIFF
  3742.             && filler_todo <= 0
  3743. #endif
  3744.             )
  3745.         {
  3746.         win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
  3747. #ifdef FEAT_VERTSPLIT
  3748.         draw_vsep_win(wp, row);
  3749. #endif
  3750.         row = endrow;
  3751.         }
  3752.  
  3753.         /* When line got too long for screen break here. */
  3754.         if (row == endrow)
  3755.         {
  3756.         ++row;
  3757.         break;
  3758.         }
  3759.  
  3760.         /*
  3761.          * Special trick to make copy/paste of wrapped lines work with
  3762.          * xterm/screen: write an extra character beyond the end of the
  3763.          * line. This will work with all terminal types (regardless of the
  3764.          * xn,am settings).
  3765.          * Only do this on a fast tty.
  3766.          * Only do this if the cursor is on the current line (something
  3767.          * has been written in it).
  3768.          * Don't do this for the GUI.
  3769.          * Don't do this for double-width characters.
  3770.          * Don't do this for a window not at the right screen border.
  3771.          */
  3772.         if (p_tf && screen_cur_row == screen_row - 1
  3773. #ifdef FEAT_GUI
  3774.              && !gui.in_use
  3775. #endif
  3776. #ifdef FEAT_DIFF
  3777.              && filler_todo <= 0
  3778. #endif
  3779. #ifdef FEAT_MBYTE
  3780.              && !(has_mbyte
  3781.              && ((*mb_off2cells)(LineOffset[screen_row]) == 2
  3782.                  || (*mb_off2cells)(LineOffset[screen_row - 1]
  3783.                             + (int)Columns - 2) == 2))
  3784. #endif
  3785.              && W_WIDTH(wp) == Columns)
  3786.         {
  3787.         /* First make sure we are at the end of the screen line, then
  3788.          * output an arbitrary character to let the terminal know
  3789.          * about the wrap. */
  3790.         if (screen_cur_col != W_WIDTH(wp))
  3791.             screen_char(LineOffset[screen_row - 1]
  3792.                               + (unsigned)Columns - 1,
  3793.                       screen_row - 1, (int)(Columns - 1));
  3794.         out_char(' ');
  3795.         /* force a redraw of the first char on the next line */
  3796.         ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
  3797.         screen_start();        /* don't know where cursor is now */
  3798.         }
  3799.  
  3800.         col = 0;
  3801.         off = (unsigned)(current_ScreenLine - ScreenLines);
  3802. #ifdef FEAT_RIGHTLEFT
  3803.         if (wp->w_p_rl)
  3804.         {
  3805.         col = W_WIDTH(wp) - 1;    /* col is not used if breaking! */
  3806.         off += col;
  3807.         }
  3808. #endif
  3809.  
  3810.         /* reset the drawing state for the start of a wrapped line */
  3811.         draw_state = WL_START;
  3812.         saved_n_extra = n_extra;
  3813.         saved_p_extra = p_extra;
  3814.         saved_c_extra = c_extra;
  3815.         saved_char_attr = char_attr;
  3816.         n_extra = 0;
  3817.         lcs_prec_todo = lcs_prec;
  3818. #ifdef FEAT_LINEBREAK
  3819. # ifdef FEAT_DIFF
  3820.         if (filler_todo <= 0)
  3821. # endif
  3822.         need_showbreak = TRUE;
  3823. #endif
  3824. #ifdef FEAT_DIFF
  3825.         --filler_todo;
  3826.         /* When the filler lines are actually below the last line of the
  3827.          * file, don't draw the line itself, break here. */
  3828.         if (filler_todo == 0 && wp->w_botfill)
  3829.         break;
  3830. #endif
  3831.     }
  3832.  
  3833.     }    /* for every character in the line */
  3834.  
  3835.     return row;
  3836. }
  3837.  
  3838. /*
  3839.  * Check whether the given character needs redrawing:
  3840.  * - the (first byte of the) character is different
  3841.  * - the attributes are different
  3842.  * - the character is multi-byte and the next byte is different
  3843.  */
  3844.     static int
  3845. char_needs_redraw(off_from, off_to, cols)
  3846.     int        off_from;
  3847.     int        off_to;
  3848.     int        cols;
  3849. {
  3850.     if (cols > 0
  3851.         && ((ScreenLines[off_from] != ScreenLines[off_to]
  3852.             || ScreenAttrs[off_from] != ScreenAttrs[off_to])
  3853.  
  3854. #ifdef FEAT_MBYTE
  3855.         || (enc_dbcs != 0
  3856.             && MB_BYTE2LEN(ScreenLines[off_from]) > 1
  3857.             && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
  3858.             ? ScreenLines2[off_from] != ScreenLines2[off_to]
  3859.             : (cols > 1 && ScreenLines[off_from + 1]
  3860.                          != ScreenLines[off_to + 1])))
  3861.         || (enc_utf8
  3862.             && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
  3863.             || (ScreenLinesUC[off_from] != 0
  3864.                 && (ScreenLinesC1[off_from]
  3865.                               != ScreenLinesC1[off_to]
  3866.                 || ScreenLinesC2[off_from]
  3867.                           != ScreenLinesC2[off_to]))))
  3868. #endif
  3869.            ))
  3870.     return TRUE;
  3871.     return FALSE;
  3872. }
  3873.  
  3874. /*
  3875.  * Move one "cooked" screen line to the screen, but only the characters that
  3876.  * have actually changed.  Handle insert/delete character.
  3877.  * "coloff" gives the first column on the screen for this line.
  3878.  * "endcol" gives the columns where valid characters are.
  3879.  * "clear_width" is the width of the window.  It's > 0 if the rest of the line
  3880.  * needs to be cleared, negative otherwise.
  3881.  * "rlflag" is TRUE in a rightleft window:
  3882.  *    When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
  3883.  *    When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
  3884.  */
  3885.     static void
  3886. screen_line(row, coloff, endcol, clear_width
  3887. #ifdef FEAT_RIGHTLEFT
  3888.                     , rlflag
  3889. #endif
  3890.                         )
  3891.     int        row;
  3892.     int        coloff;
  3893.     int        endcol;
  3894.     int        clear_width;
  3895. #ifdef FEAT_RIGHTLEFT
  3896.     int        rlflag;
  3897. #endif
  3898. {
  3899.     unsigned        off_from;
  3900.     unsigned        off_to;
  3901.     int            col = 0;
  3902. #if defined(FEAT_GUI) || defined(UNIX) || defined(FEAT_VERTSPLIT)
  3903.     int            hl;
  3904. #endif
  3905.     int            force = FALSE;    /* force update rest of the line */
  3906.     int            redraw_this        /* bool: does character need redraw? */
  3907. #ifdef FEAT_GUI
  3908.                 = TRUE    /* For GUI when while-loop empty */
  3909. #endif
  3910.                 ;
  3911.     int            redraw_next;    /* redraw_this for next character */
  3912. #ifdef FEAT_MBYTE
  3913.     int            clear_next = FALSE;
  3914.     int            char_cells;        /* 1: normal char */
  3915.                     /* 2: occupies two display cells */
  3916. # define CHAR_CELLS char_cells
  3917. #else
  3918. # define CHAR_CELLS 1
  3919. #endif
  3920.  
  3921. # ifdef FEAT_CLIPBOARD
  3922.     clip_may_clear_selection(row, row);
  3923. # endif
  3924.  
  3925.     off_from = (unsigned) (current_ScreenLine - ScreenLines);
  3926.     off_to = LineOffset[row] + coloff;
  3927.  
  3928. #ifdef FEAT_RIGHTLEFT
  3929.     if (rlflag)
  3930.     {
  3931.     /* Clear rest first, because it's left of the text. */
  3932.     if (clear_width > 0)
  3933.     {
  3934.         while (col <= endcol && ScreenLines[off_to] == ' '
  3935.                           && ScreenAttrs[off_to] == 0)
  3936.         {
  3937.         ++off_to;
  3938.         ++col;
  3939.         }
  3940.         if (col <= endcol)
  3941.         screen_fill(row, row + 1, col + coloff,
  3942.                         endcol + coloff + 1, ' ', ' ', 0);
  3943.     }
  3944.     col = endcol + 1;
  3945.     off_to = LineOffset[row] + col + coloff;
  3946.     off_from += col;
  3947.     endcol = (clear_width > 0 ? clear_width : -clear_width);
  3948.     }
  3949. #endif /* FEAT_RIGHTLEFT */
  3950.  
  3951.     redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
  3952.  
  3953.     while (col < endcol)
  3954.     {
  3955. #ifdef FEAT_MBYTE
  3956.     if (has_mbyte && (col + 1 < endcol))
  3957.         char_cells = (*mb_off2cells)(off_from);
  3958.     else
  3959.         char_cells = 1;
  3960. #endif
  3961.  
  3962.     redraw_this = redraw_next;
  3963.     redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
  3964.                   off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
  3965.  
  3966. #ifdef FEAT_GUI
  3967.     /* If the next character was bold, then redraw the current character to
  3968.      * remove any pixels that might have spilt over into us.  This only
  3969.      * happens in the GUI.
  3970.      */
  3971.     if (redraw_next && gui.in_use)
  3972.     {
  3973.         hl = ScreenAttrs[off_to + CHAR_CELLS];
  3974.         if (hl > HL_ALL || (hl & HL_BOLD))
  3975.         redraw_this = TRUE;
  3976.     }
  3977. #endif
  3978.  
  3979.     if (redraw_this)
  3980.     {
  3981.         /*
  3982.          * Special handling when 'xs' termcap flag set (hpterm):
  3983.          * Attributes for characters are stored at the position where the
  3984.          * cursor is when writing the highlighting code.  The
  3985.          * start-highlighting code must be written with the cursor on the
  3986.          * first highlighted character.  The stop-highlighting code must
  3987.          * be written with the cursor just after the last highlighted
  3988.          * character.
  3989.          * Overwriting a character doesn't remove it's highlighting.  Need
  3990.          * to clear the rest of the line, and force redrawing it
  3991.          * completely.
  3992.          */
  3993.         if (       p_wiv
  3994.             && !force
  3995. #ifdef FEAT_GUI
  3996.             && !gui.in_use
  3997. #endif
  3998.             && ScreenAttrs[off_to] != 0
  3999.             && ScreenAttrs[off_from] != ScreenAttrs[off_to])
  4000.         {
  4001.         /*
  4002.          * Need to remove highlighting attributes here.
  4003.          */
  4004.         windgoto(row, col + coloff);
  4005.         out_str(T_CE);        /* clear rest of this screen line */
  4006.         screen_start();        /* don't know where cursor is now */
  4007.         force = TRUE;        /* force redraw of rest of the line */
  4008.         redraw_next = TRUE;    /* or else next char would miss out */
  4009.  
  4010.         /*
  4011.          * If the previous character was highlighted, need to stop
  4012.          * highlighting at this character.
  4013.          */
  4014.         if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
  4015.         {
  4016.             screen_attr = ScreenAttrs[off_to - 1];
  4017.             term_windgoto(row, col + coloff);
  4018.             screen_stop_highlight();
  4019.         }
  4020.         else
  4021.             screen_attr = 0;        /* highlighting has stopped */
  4022.         }
  4023. #ifdef FEAT_MBYTE
  4024.         if (enc_dbcs != 0)
  4025.         {
  4026.         /* Check if overwriting a double-byte with a single-byte or
  4027.          * the other way around requires another character to be
  4028.          * redrawn.  For UTF-8 this isn't needed, because comparing
  4029.          * ScreenLinesUC[] is sufficient. */
  4030.         if (char_cells == 1
  4031.             && col + 1 < endcol
  4032.             && (*mb_off2cells)(off_to) > 1)
  4033.         {
  4034.             /* Writing a single-cell character over a double-cell
  4035.              * character: need to redraw the next cell. */
  4036.             ScreenLines[off_to + 1] = 0;
  4037.             redraw_next = TRUE;
  4038.         }
  4039.         else if (char_cells == 2
  4040.             && col + 2 < endcol
  4041.             && (*mb_off2cells)(off_to) == 1
  4042.             && (*mb_off2cells)(off_to + 1) > 1)
  4043.         {
  4044.             /* Writing the second half of a double-cell character over
  4045.              * a double-cell character: need to redraw the second
  4046.              * cell. */
  4047.             ScreenLines[off_to + 2] = 0;
  4048.             redraw_next = TRUE;
  4049.         }
  4050.  
  4051.         if (enc_dbcs == DBCS_JPNU)
  4052.             ScreenLines2[off_to] = ScreenLines2[off_from];
  4053.         }
  4054.         /* When writing a single-width character over a double-width
  4055.          * character and at the end of the redrawn text, need to clear out
  4056.          * the right halve of the old character. */
  4057.         if (has_mbyte && char_cells == 1 && col + 1 == endcol
  4058.             && (*mb_off2cells)(off_to) > 1)
  4059.         clear_next = TRUE;
  4060. #endif
  4061.  
  4062.         ScreenLines[off_to] = ScreenLines[off_from];
  4063. #ifdef FEAT_MBYTE
  4064.         if (enc_utf8)
  4065.         {
  4066.         ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
  4067.         ScreenLinesC1[off_to] = ScreenLinesC1[off_from];
  4068.         ScreenLinesC2[off_to] = ScreenLinesC2[off_from];
  4069.         }
  4070.         if (char_cells == 2)
  4071.         ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
  4072. #endif
  4073.  
  4074. #if defined(FEAT_GUI) || defined(UNIX)
  4075.         /* The bold trick makes a single row of pixels appear in the next
  4076.          * character.  When a bold character is removed, the next
  4077.          * character should be redrawn too.  This happens for our own GUI
  4078.          * and for some xterms. */
  4079.         if (
  4080. # ifdef FEAT_GUI
  4081.             gui.in_use
  4082. # endif
  4083. # if defined(FEAT_GUI) && defined(UNIX)
  4084.             ||
  4085. # endif
  4086. # ifdef UNIX
  4087.             term_is_xterm
  4088. # endif
  4089.             )
  4090.         {
  4091.         hl = ScreenAttrs[off_to];
  4092.         if (hl > HL_ALL || (hl & HL_BOLD))
  4093.             redraw_next = TRUE;
  4094.         }
  4095. #endif
  4096.         ScreenAttrs[off_to] = ScreenAttrs[off_from];
  4097. #ifdef FEAT_MBYTE
  4098.         if (enc_dbcs != 0 && char_cells == 2)
  4099.         {
  4100.         /* just a hack: It makes two bytes of DBCS have same attr */
  4101.         ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
  4102.         screen_char_2(off_to, row, col + coloff);
  4103.         }
  4104.         else
  4105. #endif
  4106.         screen_char(off_to, row, col + coloff);
  4107.     }
  4108.     else if (  p_wiv
  4109. #ifdef FEAT_GUI
  4110.         && !gui.in_use
  4111. #endif
  4112.         && col + coloff > 0)
  4113.     {
  4114.         if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
  4115.         {
  4116.         /*
  4117.          * Don't output stop-highlight when moving the cursor, it will
  4118.          * stop the highlighting when it should continue.
  4119.          */
  4120.         screen_attr = 0;
  4121.         }
  4122.         else if (screen_attr != 0)
  4123.         screen_stop_highlight();
  4124.     }
  4125.  
  4126.     off_to += CHAR_CELLS;
  4127.     off_from += CHAR_CELLS;
  4128.     col += CHAR_CELLS;
  4129.     }
  4130.  
  4131. #ifdef FEAT_MBYTE
  4132.     if (clear_next)
  4133.     {
  4134.     /* Clear the second half of a double-wide character of which the left
  4135.      * half was overwritten with a single-wide character. */
  4136.     ScreenLines[off_to] = ' ';
  4137.     if (enc_utf8)
  4138.         ScreenLinesUC[off_to] = 0;
  4139.     screen_char(off_to, row, col + coloff);
  4140.     }
  4141. #endif
  4142.  
  4143.     if (clear_width > 0
  4144. #ifdef FEAT_RIGHTLEFT
  4145.             && !rlflag
  4146. #endif
  4147.                    )
  4148.     {
  4149. #ifdef FEAT_GUI
  4150.     int startCol = col;
  4151. #endif
  4152.  
  4153.     /* blank out the rest of the line */
  4154.     while (col < clear_width && ScreenLines[off_to] == ' '
  4155.                           && ScreenAttrs[off_to] == 0)
  4156.     {
  4157.         ++off_to;
  4158.         ++col;
  4159.     }
  4160.     if (col < clear_width)
  4161.     {
  4162. #ifdef FEAT_GUI
  4163.         /*
  4164.          * In the GUI, clearing the rest of the line may leave pixels
  4165.          * behind if the first character cleared was bold.  Some bold
  4166.          * fonts spill over the left.  In this case we redraw the previous
  4167.          * character too.  If we didn't skip any blanks above, then we
  4168.          * only redraw if the character wasn't already redrawn anyway.
  4169.          */
  4170.         if (gui.in_use && (col > startCol || !redraw_this)
  4171. # ifdef FEAT_MBYTE
  4172.             && enc_dbcs == 0
  4173. # endif
  4174.            )
  4175.         {
  4176.         hl = ScreenAttrs[off_to];
  4177.         if (hl > HL_ALL || (hl & HL_BOLD))
  4178.             screen_char(off_to - 1, row, col + coloff - 1);
  4179.         }
  4180. #endif
  4181.         screen_fill(row, row + 1, col + coloff, clear_width + coloff,
  4182.                                  ' ', ' ', 0);
  4183. #ifdef FEAT_VERTSPLIT
  4184.         off_to += clear_width - col;
  4185.         col = clear_width;
  4186. #endif
  4187.     }
  4188.     }
  4189.  
  4190. #ifdef FEAT_VERTSPLIT
  4191.     if (clear_width > 0)
  4192.     {
  4193.     /* For a window that's left of another, draw the separator char. */
  4194.     if (col + coloff < Columns)
  4195.     {
  4196.         int c;
  4197.  
  4198.         c = fillchar_vsep(&hl);
  4199.         if (ScreenLines[off_to] != c || ScreenAttrs[off_to] != hl)
  4200.         {
  4201.         ScreenLines[off_to] = c;
  4202.         ScreenAttrs[off_to] = hl;
  4203. # ifdef FEAT_MBYTE
  4204.         if (enc_utf8)
  4205.             ScreenLinesUC[off_to] = 0;
  4206. # endif
  4207.         screen_char(off_to, row, col + coloff);
  4208.         }
  4209.     }
  4210.     }
  4211. #endif
  4212. }
  4213.  
  4214. #if defined(FEAT_WINDOWS) || defined(PROTO)
  4215. /*
  4216.  * mark all status lines for redraw; used after first :cd
  4217.  */
  4218.     void
  4219. status_redraw_all()
  4220. {
  4221.     win_T    *wp;
  4222.  
  4223.     for (wp = firstwin; wp; wp = wp->w_next)
  4224.     if (wp->w_status_height)
  4225.     {
  4226.         wp->w_redr_status = TRUE;
  4227.         redraw_later(VALID);
  4228.     }
  4229. }
  4230.  
  4231. /*
  4232.  * mark all status lines of the current buffer for redraw
  4233.  */
  4234.     void
  4235. status_redraw_curbuf()
  4236. {
  4237.     win_T    *wp;
  4238.  
  4239.     for (wp = firstwin; wp; wp = wp->w_next)
  4240.     if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
  4241.     {
  4242.         wp->w_redr_status = TRUE;
  4243.         redraw_later(VALID);
  4244.     }
  4245. }
  4246.  
  4247. /*
  4248.  * Redraw all status lines that need to be redrawn.
  4249.  */
  4250.     void
  4251. redraw_statuslines()
  4252. {
  4253.     win_T    *wp;
  4254.  
  4255.     for (wp = firstwin; wp; wp = wp->w_next)
  4256.     if (wp->w_redr_status)
  4257.         win_redr_status(wp);
  4258. }
  4259. #endif
  4260.  
  4261. #if defined(FEAT_WILDMENU) && defined(FEAT_VERTSPLIT)
  4262. /*
  4263.  * Redraw all status lines at the bottom of frame "frp".
  4264.  */
  4265.     static void
  4266. win_redraw_last_status(frp)
  4267.     frame_T    *frp;
  4268. {
  4269.     if (frp->fr_layout == FR_LEAF)
  4270.     frp->fr_win->w_redr_status = TRUE;
  4271.     else if (frp->fr_layout == FR_ROW)
  4272.     {
  4273.     for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
  4274.         win_redraw_last_status(frp);
  4275.     }
  4276.     else /* frp->fr_layout == FR_COL */
  4277.     {
  4278.     frp = frp->fr_child;
  4279.     while (frp->fr_next != NULL)
  4280.         frp = frp->fr_next;
  4281.     win_redraw_last_status(frp);
  4282.     }
  4283. }
  4284. #endif
  4285.  
  4286. #ifdef FEAT_VERTSPLIT
  4287. /*
  4288.  * Draw the verticap separator right of window "wp" starting with line "row".
  4289.  */
  4290.     static void
  4291. draw_vsep_win(wp, row)
  4292.     win_T    *wp;
  4293.     int        row;
  4294. {
  4295.     int        hl;
  4296.     int        c;
  4297.  
  4298.     if (wp->w_vsep_width)
  4299.     {
  4300.     /* draw the vertical separator right of this window */
  4301.     c = fillchar_vsep(&hl);
  4302.     screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
  4303.         W_ENDCOL(wp), W_ENDCOL(wp) + 1,
  4304.         c, ' ', hl);
  4305.     }
  4306. }
  4307. #endif
  4308.  
  4309. #ifdef FEAT_WILDMENU
  4310. /*
  4311.  * Private gettail for win_redr_status_matches(): Find tail of file name path
  4312.  * but ignore trailing "/".
  4313.  */
  4314. static char_u *wm_gettail __ARGS((char_u *s));
  4315. static int status_match_len __ARGS((expand_T *xp, char_u *s));
  4316.  
  4317.     static char_u *
  4318. wm_gettail(s)
  4319.     char_u    *s;
  4320. {
  4321.     char_u    *p;
  4322.     char_u    *t = s;
  4323.     int        had_sep = FALSE;
  4324.  
  4325.     for (p = s; *p != NUL; )
  4326.     {
  4327.     if (vim_ispathsep(*p))
  4328.         had_sep = TRUE;
  4329.     else if (had_sep)
  4330.     {
  4331.         t = p;
  4332.         had_sep = FALSE;
  4333.     }
  4334. #ifdef FEAT_MBYTE
  4335.     if (has_mbyte)
  4336.         p += (*mb_ptr2len_check)(p);
  4337.     else
  4338. #endif
  4339.         ++p;
  4340.     }
  4341.     return t;
  4342. }
  4343.  
  4344. /*
  4345.  * Get the lenght of an item as it will be shown in that status line.
  4346.  */
  4347.     static int
  4348. status_match_len(xp, s)
  4349.     expand_T    *xp;
  4350.     char_u    *s;
  4351. {
  4352.     int    len = 0;
  4353.  
  4354. #ifdef FEAT_MENU
  4355.     int emenu = (xp->xp_context == EXPAND_MENUS
  4356.         || xp->xp_context == EXPAND_MENUNAMES);
  4357.  
  4358.     /* Check for menu separators - replace with '|'. */
  4359.     if (emenu && menu_is_separator(s))
  4360.     return 1;
  4361. #endif
  4362.  
  4363.     while (*s != NUL)
  4364.     {
  4365.     /* Don't display backslashes used for escaping, they look ugly. */
  4366.     if (rem_backslash(s)
  4367. #ifdef FEAT_MENU
  4368.         || (emenu && (s[0] == '\\' && s[1] != NUL))
  4369. #endif
  4370.         )
  4371.         ++s;
  4372. #ifdef FEAT_MBYTE
  4373.     if (has_mbyte)
  4374.     {
  4375.         len += ptr2cells(s);
  4376.         s += (*mb_ptr2len_check)(s);
  4377.     }
  4378.     else
  4379. #endif
  4380.         len += ptr2cells(s++);
  4381.  
  4382.     }
  4383.  
  4384.     return len;
  4385. }
  4386.  
  4387. /*
  4388.  * Show wildchar matches in the status line.
  4389.  * Show at least the "match" item.
  4390.  * We start at item 'first_match' in the list and show all matches that fit.
  4391.  *
  4392.  * If inversion is possible we use it. Else '=' characters are used.
  4393.  */
  4394.     void
  4395. win_redr_status_matches(xp, num_matches, matches, match)
  4396.     expand_T    *xp;
  4397.     int        num_matches;
  4398.     char_u    **matches;    /* list of matches */
  4399.     int        match;
  4400. {
  4401. #define L_MATCH(m) (fmatch ? wm_gettail(matches[m]) : matches[m])
  4402.     int        fmatch = (xp->xp_context == EXPAND_FILES);
  4403.  
  4404.     int        row;
  4405.     char_u    *buf;
  4406.     int        len;
  4407.     int        clen;        /* lenght in screen cells */
  4408.     int        fillchar;
  4409.     int        attr;
  4410.     int        i;
  4411.     int        highlight = TRUE;
  4412.     char_u    *selstart = NULL;
  4413.     int        selstart_col = 0;
  4414.     char_u    *selend = NULL;
  4415.     static int    first_match = 0;
  4416.     int        add_left = FALSE;
  4417.     char_u    *s;
  4418. #ifdef FEAT_MENU
  4419.     int        emenu;
  4420. #endif
  4421. #if defined(FEAT_MBYTE) || defined(FEAT_MENU)
  4422.     int        l;
  4423. #endif
  4424.  
  4425.     if (matches == NULL)    /* interrupted completion? */
  4426.     return;
  4427.  
  4428.     buf = alloc((unsigned)Columns + 1);
  4429.     if (buf == NULL)
  4430.     return;
  4431.  
  4432.     if (match == -1)    /* don't show match but original text */
  4433.     {
  4434.     match = 0;
  4435.     highlight = FALSE;
  4436.     }
  4437.     /* count 1 for the ending ">" */
  4438.     clen = status_match_len(xp, L_MATCH(match)) + 3;
  4439.     if (match == 0)
  4440.     first_match = 0;
  4441.     else if (match < first_match)
  4442.     {
  4443.     /* jumping left, as far as we can go */
  4444.     first_match = match;
  4445.     add_left = TRUE;
  4446.     }
  4447.     else
  4448.     {
  4449.     /* check if match fits on the screen */
  4450.     for (i = first_match; i < match; ++i)
  4451.         clen += status_match_len(xp, L_MATCH(i)) + 2;
  4452.     if (first_match > 0)
  4453.         clen += 2;
  4454.     /* jumping right, put match at the left */
  4455.     if ((long)clen > Columns)
  4456.     {
  4457.         first_match = match;
  4458.         /* if showing the last match, we can add some on the left */
  4459.         clen = 2;
  4460.         for (i = match; i < num_matches; ++i)
  4461.         {
  4462.         clen += status_match_len(xp, L_MATCH(i)) + 2;
  4463.         if ((long)clen >= Columns)
  4464.             break;
  4465.         }
  4466.         if (i == num_matches)
  4467.         add_left = TRUE;
  4468.     }
  4469.     }
  4470.     if (add_left)
  4471.     while (first_match > 0)
  4472.     {
  4473.         clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
  4474.         if ((long)clen >= Columns)
  4475.         break;
  4476.         --first_match;
  4477.     }
  4478.  
  4479.     fillchar = fillchar_status(&attr, TRUE);
  4480.  
  4481.     if (first_match == 0)
  4482.     {
  4483.     *buf = NUL;
  4484.     len = 0;
  4485.     }
  4486.     else
  4487.     {
  4488.     STRCPY(buf, "< ");
  4489.     len = 2;
  4490.     }
  4491.     clen = len;
  4492.  
  4493.     i = first_match;
  4494.     while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
  4495.     {
  4496.     if (i == match)
  4497.     {
  4498.         selstart = buf + len;
  4499.         selstart_col = clen;
  4500.     }
  4501.  
  4502.     s = L_MATCH(i);
  4503.     /* Check for menu separators - replace with '|' */
  4504. #ifdef FEAT_MENU
  4505.     emenu = (xp->xp_context == EXPAND_MENUS
  4506.         || xp->xp_context == EXPAND_MENUNAMES);
  4507.     if (emenu && menu_is_separator(s))
  4508.     {
  4509.         STRCPY(buf + len, transchar('|'));
  4510.         l = (int)STRLEN(buf + len);
  4511.         len += l;
  4512.         clen += l;
  4513.     }
  4514.     else
  4515. #endif
  4516.         for ( ; *s != NUL; ++s)
  4517.     {
  4518.         /* Don't display backslashes used for escaping, they look ugly. */
  4519.         if (rem_backslash(s)
  4520. #ifdef FEAT_MENU
  4521.             || (emenu
  4522.               && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
  4523. #endif
  4524.             )
  4525.         ++s;
  4526.         clen += ptr2cells(s);
  4527. #ifdef FEAT_MBYTE
  4528.         if (has_mbyte && (l = (*mb_ptr2len_check)(s)) > 1)
  4529.         {
  4530.         STRNCPY(buf + len, s, l);
  4531.         s += l - 1;
  4532.         len += l;
  4533.         }
  4534.         else
  4535. #endif
  4536.         {
  4537.         STRCPY(buf + len, transchar(*s));
  4538.         len += (int)STRLEN(buf + len);
  4539.         }
  4540.     }
  4541.     if (i == match)
  4542.         selend = buf + len;
  4543.  
  4544.     *(buf + len++) = ' ';
  4545.     *(buf + len++) = ' ';
  4546.     clen += 2;
  4547.     if (++i == num_matches)
  4548.         break;
  4549.     }
  4550.  
  4551.     if (i != num_matches)
  4552.     {
  4553.     *(buf + len++) = '>';
  4554.     ++clen;
  4555.     }
  4556.  
  4557.     buf[len] = NUL;
  4558.  
  4559.     row = cmdline_row - 1;
  4560.     if (row >= 0)
  4561.     {
  4562.     if (!wild_menu_showing)
  4563.     {
  4564.         if (msg_scrolled && !wild_menu_showing)
  4565.         {
  4566.         /* Put the wildmenu just above the command line.  If there is
  4567.          * no room, scroll the screen one line up. */
  4568.         if (cmdline_row == Rows - 1)
  4569.         {
  4570.             screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
  4571.             ++msg_scrolled;
  4572.         }
  4573.         else
  4574.         {
  4575.             ++cmdline_row;
  4576.             ++row;
  4577.         }
  4578.         wild_menu_showing = WM_SCROLLED;
  4579.         }
  4580.         else
  4581.         {
  4582.         /* create status line if needed */
  4583.         if (lastwin->w_status_height == 0)
  4584.         {
  4585.             save_p_ls = p_ls;
  4586.             p_ls = 2;
  4587.             last_status(FALSE);
  4588.         }
  4589.         wild_menu_showing = WM_SHOWN;
  4590.         }
  4591.     }
  4592.  
  4593.     screen_puts(buf, row, 0, attr);
  4594.     if (selstart != NULL && highlight)
  4595.     {
  4596.         *selend = NUL;
  4597.         screen_puts(selstart, row, selstart_col, hl_attr(HLF_WM));
  4598.     }
  4599.  
  4600.     screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
  4601.     }
  4602.  
  4603. #ifdef FEAT_VERTSPLIT
  4604.     win_redraw_last_status(topframe);
  4605. #else
  4606.     lastwin->w_redr_status = TRUE;
  4607. #endif
  4608.     vim_free(buf);
  4609. }
  4610. #endif
  4611.  
  4612. #if defined(FEAT_WINDOWS) || defined(PROTO)
  4613. /*
  4614.  * Redraw the status line of window wp.
  4615.  *
  4616.  * If inversion is possible we use it. Else '=' characters are used.
  4617.  */
  4618.     void
  4619. win_redr_status(wp)
  4620.     win_T    *wp;
  4621. {
  4622.     int        row;
  4623.     char_u    *p;
  4624.     int        len;
  4625.     int        fillchar;
  4626.     int        attr;
  4627.     int        this_ru_col;
  4628.  
  4629.     wp->w_redr_status = FALSE;
  4630.     if (wp->w_status_height == 0)
  4631.     {
  4632.     /* no status line, can only be last window */
  4633.     redraw_cmdline = TRUE;
  4634.     }
  4635.     else if (!redrawing())
  4636.     {
  4637.     /* Don't redraw right now, do it later. */
  4638.     wp->w_redr_status = TRUE;
  4639.     }
  4640. #ifdef FEAT_STL_OPT
  4641.     else if (*p_stl)
  4642.     {
  4643.     /* redraw custom status line */
  4644.     win_redr_custom(wp, FALSE);
  4645.     }
  4646. #endif
  4647.     else
  4648.     {
  4649.     fillchar = fillchar_status(&attr, wp == curwin);
  4650.  
  4651.     if (buf_spname(wp->w_buffer) != NULL)
  4652.         STRCPY(NameBuff, buf_spname(wp->w_buffer));
  4653.     else
  4654.     {
  4655.         home_replace(wp->w_buffer, wp->w_buffer->b_fname, NameBuff,
  4656.                                   MAXPATHL, TRUE);
  4657.         trans_characters(NameBuff, MAXPATHL);
  4658.     }
  4659.     p = NameBuff;
  4660.     len = (int)STRLEN(p);
  4661.  
  4662.     if (wp->w_buffer->b_help
  4663. #ifdef FEAT_QUICKFIX
  4664.         || wp->w_p_pvw
  4665. #endif
  4666.         || bufIsChanged(wp->w_buffer)
  4667.         || wp->w_buffer->b_p_ro)
  4668.         *(p + len++) = ' ';
  4669.     if (wp->w_buffer->b_help)
  4670.     {
  4671.         STRCPY(p + len, _("[help]"));
  4672.         len += (int)STRLEN(p + len);
  4673.     }
  4674. #ifdef FEAT_QUICKFIX
  4675.     if (wp->w_p_pvw)
  4676.     {
  4677.         STRCPY(p + len, _("[Preview]"));
  4678.         len += (int)STRLEN(p + len);
  4679.     }
  4680. #endif
  4681.     if (bufIsChanged(wp->w_buffer))
  4682.     {
  4683.         STRCPY(p + len, "[+]");
  4684.         len += 3;
  4685.     }
  4686.     if (wp->w_buffer->b_p_ro)
  4687.     {
  4688.         STRCPY(p + len, "[RO]");
  4689.         len += 4;
  4690.     }
  4691.  
  4692. #ifndef FEAT_VERTSPLIT
  4693.     this_ru_col = ru_col;
  4694.     if (this_ru_col < (Columns + 1) / 2)
  4695.         this_ru_col = (Columns + 1) / 2;
  4696. #else
  4697.     this_ru_col = ru_col - (Columns - W_WIDTH(wp));
  4698.     if (this_ru_col < (W_WIDTH(wp) + 1) / 2)
  4699.         this_ru_col = (W_WIDTH(wp) + 1) / 2;
  4700.     if (this_ru_col <= 1)
  4701.     {
  4702.         p = (char_u *)"<";        /* No room for file name! */
  4703.         len = 1;
  4704.     }
  4705.     else
  4706. #endif
  4707. #ifdef FEAT_MBYTE
  4708.         if (has_mbyte)
  4709.         {
  4710.         int    clen = 0, i;
  4711.  
  4712.         p[len] = NUL;
  4713.         /* Count total number of display cells. */
  4714.         for (i = 0; p[i] != NUL; i += (*mb_ptr2len_check)(p + i))
  4715.             clen += (*mb_ptr2cells)(p + i);
  4716.         /* Find first character that will fit.
  4717.          * Going from start to end is much faster for DBCS. */
  4718.         for (i = 0; p[i] != NUL && clen > this_ru_col - 1;
  4719.                           i += (*mb_ptr2len_check)(p + i))
  4720.             clen -= (*mb_ptr2cells)(p + i);
  4721.         if (i > 0)
  4722.         {
  4723.             p = p + i - 1;
  4724.             *p = '<';
  4725.             len = len - i + 1;
  4726.         }
  4727.  
  4728.         }
  4729.         else
  4730. #endif
  4731.         if (len > this_ru_col - 1)
  4732.         {
  4733.         p += len - (this_ru_col - 1);
  4734.         *p = '<';
  4735.         len = this_ru_col - 1;
  4736.         }
  4737.  
  4738.     row = W_WINROW(wp) + wp->w_height;
  4739.     screen_puts(p, row, W_WINCOL(wp), attr);
  4740.     screen_fill(row, row + 1, len + W_WINCOL(wp),
  4741.             this_ru_col + W_WINCOL(wp), fillchar, fillchar, attr);
  4742.  
  4743.     if (get_keymap_str(wp, NameBuff, MAXPATHL)
  4744.         && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
  4745.         screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
  4746.                            - 1 + W_WINCOL(wp)), attr);
  4747.  
  4748. #ifdef FEAT_CMDL_INFO
  4749.     win_redr_ruler(wp, TRUE);
  4750. #endif
  4751.     }
  4752.  
  4753. #ifdef FEAT_VERTSPLIT
  4754.     /*
  4755.      * May need to draw the character below the vertical separator.
  4756.      */
  4757.     if (wp->w_vsep_width != 0)
  4758.     {
  4759.     if (stl_connected(wp))
  4760.         fillchar = fillchar_status(&attr, wp == curwin);
  4761.     else
  4762.         fillchar = fillchar_vsep(&attr);
  4763.     screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
  4764.                                     attr);
  4765.     }
  4766. #endif
  4767. }
  4768.  
  4769. # ifdef FEAT_VERTSPLIT
  4770. /*
  4771.  * Return TRUE if the status line of window "wp" is connected to the status
  4772.  * line of the window right of it.  If not, then it's a vertical separator.
  4773.  * Only call if (wp->w_vsep_width != 0).
  4774.  */
  4775.     int
  4776. stl_connected(wp)
  4777.     win_T    *wp;
  4778. {
  4779.     frame_T    *fr;
  4780.  
  4781.     fr = wp->w_frame;
  4782.     while (fr->fr_parent != NULL)
  4783.     {
  4784.     if (fr->fr_parent->fr_layout == FR_COL)
  4785.     {
  4786.         if (fr->fr_next != NULL)
  4787.         break;
  4788.     }
  4789.     else
  4790.     {
  4791.         if (fr->fr_next != NULL)
  4792.         return TRUE;
  4793.     }
  4794.     fr = fr->fr_parent;
  4795.     }
  4796.     return FALSE;
  4797. }
  4798. # endif
  4799.  
  4800. #endif /* FEAT_WINDOWS */
  4801.  
  4802. #if defined(FEAT_WINDOWS) || defined(FEAT_STL_OPT) || defined(PROTO)
  4803. /*
  4804.  * Get the value to show for the language mappings, active 'keymap'.
  4805.  */
  4806.     int
  4807. get_keymap_str(wp, buf, len)
  4808.     win_T    *wp;
  4809.     char_u    *buf;        /* buffer for the result */
  4810.     int        len;        /* length of buffer */
  4811. {
  4812.     char_u    *p;
  4813.  
  4814.     if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
  4815.     return FALSE;
  4816.  
  4817.     {
  4818. #ifdef FEAT_EVAL
  4819.     buf_T    *old_curbuf = curbuf;
  4820.     win_T    *old_curwin = curwin;
  4821.     char_u    *s;
  4822.  
  4823.     curbuf = wp->w_buffer;
  4824.     curwin = wp;
  4825.     STRCPY(buf, "b:keymap_name");    /* must be writable */
  4826.     ++emsg_skip;
  4827.     s = p = eval_to_string(buf, NULL);
  4828.     --emsg_skip;
  4829.     curbuf = old_curbuf;
  4830.     curwin = old_curwin;
  4831.     if (p == NULL || *p == NUL)
  4832. #endif
  4833.     {
  4834. #ifdef FEAT_KEYMAP
  4835.         if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
  4836.         p = wp->w_buffer->b_p_keymap;
  4837.         else
  4838. #endif
  4839.         p = (char_u *)"lang";
  4840.     }
  4841.     if ((int)(STRLEN(p) + 3) < len)
  4842.         sprintf((char *)buf, "<%s>", p);
  4843.     else
  4844.         buf[0] = NUL;
  4845. #ifdef FEAT_EVAL
  4846.     vim_free(s);
  4847. #endif
  4848.     }
  4849.     return buf[0] != NUL;
  4850. }
  4851. #endif
  4852.  
  4853. #if defined(FEAT_STL_OPT) || defined(PROTO)
  4854. /*
  4855.  * Redraw the status line or ruler of window wp.
  4856.  */
  4857.     static void
  4858. win_redr_custom(wp, Ruler)
  4859.     win_T    *wp;
  4860.     int        Ruler;
  4861. {
  4862.     int        attr;
  4863.     int        curattr;
  4864.     int        row;
  4865.     int        col = 0;
  4866.     int        maxlen;
  4867.     int        n;
  4868.     int        len;
  4869.     int        fillchar;
  4870.     char_u    buf[MAXPATHL];
  4871.     char_u    *p;
  4872.     char_u    c;
  4873.     struct    stl_hlrec hl[STL_MAX_ITEM];
  4874.  
  4875.     /* setup environment for the task at hand */
  4876.     row = W_WINROW(wp) + wp->w_height;
  4877.     fillchar = fillchar_status(&attr, wp == curwin);
  4878.     maxlen = W_WIDTH(wp);
  4879.     p = p_stl;
  4880.     if (Ruler)
  4881.     {
  4882.     p = p_ruf;
  4883.     /* advance past any leading group spec - implicit in ru_col */
  4884.     if (*p == '%')
  4885.     {
  4886.         if (*++p == '-')
  4887.         p++;
  4888.         if (atoi((char *) p))
  4889.         while (isdigit(*p))
  4890.             p++;
  4891.         if (*p++ != '(')
  4892.         p = p_ruf;
  4893.     }
  4894. #ifdef FEAT_VERTSPLIT
  4895.     col = ru_col - (Columns - W_WIDTH(wp));
  4896.     if (col < (W_WIDTH(wp) + 1) / 2)
  4897.         col = (W_WIDTH(wp) + 1) / 2;
  4898. #else
  4899.     col = ru_col;
  4900.     if (col > (Columns + 1) / 2)
  4901.         col = (Columns + 1) / 2;
  4902. #endif
  4903.     maxlen = W_WIDTH(wp) - col;
  4904. #ifdef FEAT_WINDOWS
  4905.     if (!wp->w_status_height)
  4906. #endif
  4907.     {
  4908.         row = Rows - 1;
  4909.         --maxlen;    /* writing in last column may cause scrolling */
  4910.         fillchar = ' ';
  4911.         attr = 0;
  4912.     }
  4913.     }
  4914.     if (maxlen >= sizeof(buf))
  4915.     maxlen = sizeof(buf) - 1;
  4916.     if (maxlen <= 0)
  4917.     return;
  4918. #ifdef FEAT_VERTSPLIT
  4919.     col += W_WINCOL(wp);
  4920. #endif
  4921.  
  4922.     len = build_stl_str_hl(wp, buf, p, fillchar, maxlen, hl);
  4923.  
  4924.     for (p = buf + len; p < buf + maxlen; p++)
  4925.     *p = fillchar;
  4926.     buf[maxlen] = 0;
  4927.  
  4928.     curattr = attr;
  4929.     p = buf;
  4930.     for (n = 0; hl[n].start != NULL; n++)
  4931.     {
  4932.     c = hl[n].start[0];
  4933.     hl[n].start[0] = 0;
  4934.     screen_puts(p, row, col, curattr);
  4935.  
  4936.     hl[n].start[0] = c;
  4937.     col += (int)(hl[n].start - p);
  4938.     p = hl[n].start;
  4939.  
  4940.     if (hl[n].userhl == 0)
  4941.         curattr = attr;
  4942. #ifdef FEAT_WINDOWS
  4943.     else if (wp != curwin && wp->w_status_height != 0)
  4944.         curattr = highlight_stlnc[hl[n].userhl - 1];
  4945. #endif
  4946.     else
  4947.         curattr = highlight_user[hl[n].userhl - 1];
  4948.     }
  4949.     screen_puts(p, row, col, curattr);
  4950. }
  4951.  
  4952. #endif /* FEAT_STL_OPT */
  4953.  
  4954. /*
  4955.  * Output a single character directly to the screen and update ScreenLines.
  4956.  * Not for multi-byte chars!
  4957.  */
  4958.     void
  4959. screen_putchar(c, row, col, attr)
  4960.     int        c;
  4961.     int        row, col;
  4962.     int        attr;
  4963. {
  4964.     char_u    buf[2];
  4965.  
  4966.     {
  4967.     buf[0] = c;
  4968.     buf[1] = NUL;
  4969.     screen_puts(buf, row, col, attr);
  4970.     }
  4971. }
  4972.  
  4973. /*
  4974.  * Get a single character directly from ScreenLines.
  4975.  * Also return its attribute in *attrp;
  4976.  * For multi-byte chars only the first byte is obtained!
  4977.  */
  4978.     int
  4979. screen_getchar(row, col, attrp)
  4980.     int        row, col;
  4981.     int        *attrp;
  4982. {
  4983.     unsigned off;
  4984.  
  4985.     /* safety check */
  4986.     if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
  4987.     {
  4988.     off = LineOffset[row] + col;
  4989.     *attrp = ScreenAttrs[off];
  4990.     return ScreenLines[off];
  4991.     }
  4992.     return 0;
  4993. }
  4994.  
  4995. /*
  4996.  * Put string '*text' on the screen at position 'row' and 'col', with
  4997.  * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
  4998.  * Note: only outputs within one row, message is truncated at screen boundary!
  4999.  * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
  5000.  */
  5001.     void
  5002. screen_puts(text, row, col, attr)
  5003.     char_u    *text;
  5004.     int        row;
  5005.     int        col;
  5006.     int        attr;
  5007. {
  5008.     unsigned    off;
  5009.     char_u    *ptr = text;
  5010. #ifdef FEAT_MBYTE
  5011.     int        mbyte_blen = 1;
  5012.     int        mbyte_cells = 1;
  5013.     int        u8c = 0;
  5014.     int        u8c_c1 = 0;
  5015.     int        u8c_c2 = 0;
  5016.     int        clear_next_cell = FALSE;
  5017. #endif
  5018.  
  5019.     if (ScreenLines != NULL && row < screen_Rows)    /* safety check */
  5020.     {
  5021.     off = LineOffset[row] + col;
  5022.     while (*ptr != NUL && col < screen_Columns)
  5023.     {
  5024. #ifdef FEAT_MBYTE
  5025.         /* check if this is the first byte of a multibyte */
  5026.         if (has_mbyte)
  5027.         {
  5028.         mbyte_blen = (*mb_ptr2len_check)(ptr);
  5029.         if (enc_dbcs == DBCS_JPNU && *ptr == 0x8e)
  5030.             mbyte_cells = 1;
  5031.         else if (enc_dbcs != 0)
  5032.             mbyte_cells = mbyte_blen;
  5033.         else    /* enc_utf8 */
  5034.         {
  5035.             u8c = utfc_ptr2char(ptr, &u8c_c1, &u8c_c2);
  5036.             mbyte_cells = utf_char2cells(u8c);
  5037.         }
  5038.         }
  5039. #endif
  5040.  
  5041.         if (ScreenLines[off] != *ptr
  5042. #ifdef FEAT_MBYTE
  5043.             || (mbyte_cells == 2
  5044.             && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
  5045.             || (enc_dbcs == DBCS_JPNU
  5046.             && *ptr == 0x8e
  5047.             && ScreenLines2[off] != ptr[1])
  5048.             || (enc_utf8
  5049.             && mbyte_blen > 1
  5050.             && (ScreenLinesUC[off] != u8c
  5051.                 || ScreenLinesC1[off] != u8c_c1
  5052.                 || ScreenLinesC2[off] != u8c_c2))
  5053. #endif
  5054.             || ScreenAttrs[off] != attr
  5055.             || exmode_active
  5056.             )
  5057.         {
  5058. #if defined(FEAT_GUI) || defined(UNIX)
  5059.         /* The bold trick makes a single row of pixels appear in the
  5060.          * next character.  When a bold character is removed, the next
  5061.          * character should be redrawn too.  This happens for our own
  5062.          * GUI and for some xterms.
  5063.          * Don't do this for the last drawn character, because the
  5064.          * next character may not be redrawn. */
  5065.         if (
  5066. # ifdef FEAT_GUI
  5067.             gui.in_use
  5068. # endif
  5069. # if defined(FEAT_GUI) && defined(UNIX)
  5070.             ||
  5071. # endif
  5072. # ifdef UNIX
  5073.             term_is_xterm
  5074. # endif
  5075.            )
  5076.         {
  5077.             int        n;
  5078.  
  5079.             n = ScreenAttrs[off];
  5080. # ifdef FEAT_MBYTE
  5081.             if (col + 1 + mbyte_cells - 1 < screen_Columns
  5082.                 && (n > HL_ALL || (n & HL_BOLD))
  5083.                 && ptr[mbyte_blen] != NUL)
  5084.             ScreenLines[off + 1 + mbyte_cells - 1] = 0;
  5085. # else
  5086.             if (col + 1 < screen_Columns
  5087.                 && (n > HL_ALL || (n & HL_BOLD))
  5088.                 && ptr[1] != NUL)
  5089.             ScreenLines[off + 1] = 0;
  5090. # endif
  5091.         }
  5092. #endif
  5093. #ifdef FEAT_MBYTE
  5094.         /* When at the end of the text and overwriting a two-cell
  5095.          * character with a one-cell character, need to clear the next
  5096.          * cell. */
  5097.         if (has_mbyte && mbyte_cells == 1 && ptr[mbyte_blen] == NUL
  5098.             && (*mb_off2cells)(off) > 1)
  5099.             clear_next_cell = TRUE;
  5100. #endif
  5101.         ScreenLines[off] = *ptr;
  5102.         ScreenAttrs[off] = attr;
  5103. #ifdef FEAT_MBYTE
  5104.         if (enc_utf8)
  5105.         {
  5106.             if (*ptr < 0x80 && u8c_c1 == 0 && u8c_c2 == 0)
  5107.             ScreenLinesUC[off] = 0;
  5108.             else
  5109.             {
  5110.             ScreenLinesUC[off] = u8c;
  5111.             ScreenLinesC1[off] = u8c_c1;
  5112.             ScreenLinesC2[off] = u8c_c2;
  5113.             }
  5114.             if (mbyte_cells == 2)
  5115.             {
  5116.             ScreenLines[off + 1] = 0;
  5117.             ScreenAttrs[off + 1] = attr;
  5118.             }
  5119.             screen_char(off, row, col);
  5120.         }
  5121.         else if (mbyte_cells == 2)
  5122.         {
  5123.             ScreenLines[off + 1] = ptr[1];
  5124.             ScreenAttrs[off + 1] = attr;
  5125.             screen_char_2(off, row, col);
  5126.         }
  5127.         else if (enc_dbcs == DBCS_JPNU && *ptr == 0x8e)
  5128.         {
  5129.             ScreenLines2[off] = ptr[1];
  5130.             screen_char(off, row, col);
  5131.         }
  5132.         else
  5133. #endif
  5134.             screen_char(off, row, col);
  5135.         }
  5136. #ifdef FEAT_MBYTE
  5137.         if (has_mbyte)
  5138.         {
  5139.         off += mbyte_cells;
  5140.         col += mbyte_cells;
  5141.         ptr += mbyte_blen;
  5142.         if (clear_next_cell)
  5143.         {
  5144.             ptr = (char_u *)" ";
  5145.             clear_next_cell = FALSE;
  5146.         }
  5147.         }
  5148.         else
  5149. #endif
  5150.         {
  5151.         ++off;
  5152.         ++col;
  5153.         ++ptr;
  5154.         }
  5155.     }
  5156.     }
  5157. }
  5158.  
  5159. #ifdef FEAT_SEARCH_EXTRA
  5160. /*
  5161.  * Prepare for 'searchhl' highlighting.
  5162.  */
  5163.     static void
  5164. start_search_hl()
  5165. {
  5166.     if (p_hls && !no_hlsearch)
  5167.     {
  5168.     last_pat_prog(&search_hl.rm);
  5169.     search_hl.attr = hl_attr(HLF_L);
  5170.     }
  5171. }
  5172.  
  5173. /*
  5174.  * Clean up for 'searchhl' highlighting.
  5175.  */
  5176.     static void
  5177. end_search_hl()
  5178. {
  5179.     if (search_hl.rm.regprog != NULL)
  5180.     {
  5181.     vim_free(search_hl.rm.regprog);
  5182.     search_hl.rm.regprog = NULL;
  5183.     }
  5184. }
  5185.  
  5186. /*
  5187.  * Advance to the match in window "wp" line "lnum" or past it.
  5188.  */
  5189.     static void
  5190. prepare_search_hl(wp, lnum)
  5191.     win_T    *wp;
  5192.     linenr_T    lnum;
  5193. {
  5194.     match_T    *shl;        /* points to search_hl or match_hl */
  5195.     int        n;
  5196.  
  5197.     /*
  5198.      * When using a multi-line pattern, start searching at the top
  5199.      * of the window or just after a closed fold.
  5200.      * Do this both for search_hl and match_hl.
  5201.      */
  5202.     shl = &search_hl;
  5203.     for (;;)
  5204.     {
  5205.     if (shl->rm.regprog != NULL
  5206.         && shl->lnum == 0
  5207.         && re_multiline(shl->rm.regprog))
  5208.     {
  5209.         if (shl->first_lnum == 0)
  5210.         {
  5211. # ifdef FEAT_FOLDING
  5212.         for (shl->first_lnum = lnum;
  5213.                shl->first_lnum > wp->w_topline; --shl->first_lnum)
  5214.             if (hasFoldingWin(wp, shl->first_lnum - 1,
  5215.                               NULL, NULL, TRUE, NULL))
  5216.             break;
  5217. # else
  5218.         shl->first_lnum = wp->w_topline;
  5219. # endif
  5220.         }
  5221.         n = 0;
  5222.         while (shl->first_lnum < lnum)
  5223.         {
  5224.         next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n);
  5225.         if (shl->lnum != 0)
  5226.         {
  5227.             shl->first_lnum = shl->lnum
  5228.                     + shl->rm.endpos[0].lnum
  5229.                     - shl->rm.startpos[0].lnum;
  5230.             n = shl->rm.endpos[0].col;
  5231.         }
  5232.         else
  5233.         {
  5234.             ++shl->first_lnum;
  5235.             n = 0;
  5236.         }
  5237.         }
  5238.     }
  5239.     if (shl == &match_hl)
  5240.         break;
  5241.     shl = &match_hl;
  5242.     }
  5243. }
  5244.  
  5245. /*
  5246.  * Search for a next 'searchl' or ":match" match.
  5247.  * Uses shl->buf.
  5248.  * Sets shl->lnum and shl->rm contents.
  5249.  * Note: Assumes a previous match is always before "lnum", unless
  5250.  * shl->lnum is zero.
  5251.  * Careful: Any pointers for buffer lines will become invalid.
  5252.  */
  5253.     static void
  5254. next_search_hl(win, shl, lnum, mincol)
  5255.     win_T    *win;
  5256.     match_T    *shl;        /* points to search_hl or match_hl */
  5257.     linenr_T    lnum;
  5258.     colnr_T    mincol;        /* minimal column for a match */
  5259. {
  5260.     linenr_T    l;
  5261.     colnr_T    matchcol;
  5262.     long    nmatched;
  5263.  
  5264.     if (shl->lnum != 0)
  5265.     {
  5266.     /* Check for three situations:
  5267.      * 1. If the "lnum" is below a previous match, start a new search.
  5268.      * 2. If the previous match includes "mincol", use it.
  5269.      * 3. Continue after the previous match.
  5270.      */
  5271.     l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
  5272.     if (lnum > l)
  5273.         shl->lnum = 0;
  5274.     else if (lnum < l || shl->rm.endpos[0].col > mincol)
  5275.         return;
  5276.     }
  5277.  
  5278.     /*
  5279.      * Repeat searching for a match until one is found that includes "mincol"
  5280.      * or none is found in this line.
  5281.      */
  5282.     for (;;)
  5283.     {
  5284.     /* Three situations:
  5285.      * 1. No useful previous match: search from start of line.
  5286.      * 2. Not Vi compatible or empty match: continue at next character.
  5287.      *    Break the loop if this is beyond the end of the line.
  5288.      * 3. Vi compatible searching: continue at end of previous match.
  5289.      */
  5290.     if (shl->lnum == 0)
  5291.         matchcol = 0;
  5292.     else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
  5293.         || (shl->rm.endpos[0].lnum == 0
  5294.             && shl->rm.endpos[0].col == shl->rm.startpos[0].col))
  5295.     {
  5296.         matchcol = shl->rm.startpos[0].col + 1;
  5297.         if (ml_get_buf(shl->buf, lnum, FALSE)[matchcol - 1] == NUL)
  5298.         {
  5299.         shl->lnum = 0;
  5300.         break;
  5301.         }
  5302.     }
  5303.     else
  5304.         matchcol = shl->rm.endpos[0].col;
  5305.  
  5306.     shl->lnum = lnum;
  5307.     nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol);
  5308.     if (nmatched == 0)
  5309.     {
  5310.         shl->lnum = 0;        /* no match found */
  5311.         break;
  5312.     }
  5313.     if (shl->rm.startpos[0].lnum > 0
  5314.         || shl->rm.startpos[0].col >= mincol
  5315.         || nmatched > 1
  5316.         || shl->rm.endpos[0].col > mincol)
  5317.     {
  5318.         shl->lnum += shl->rm.startpos[0].lnum;
  5319.         break;            /* useful match found */
  5320.     }
  5321.     }
  5322. }
  5323. #endif
  5324.  
  5325.       static void
  5326. screen_start_highlight(attr)
  5327.       int    attr;
  5328. {
  5329.     attrentry_T *aep = NULL;
  5330.  
  5331.     screen_attr = attr;
  5332.     if (full_screen
  5333. #ifdef WIN3264
  5334.             && termcap_active
  5335. #endif
  5336.                        )
  5337.     {
  5338. #ifdef FEAT_GUI
  5339.     if (gui.in_use)
  5340.     {
  5341.         char    buf[20];
  5342.  
  5343.         sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);        /* internal GUI code */
  5344.         OUT_STR(buf);
  5345.     }
  5346.     else
  5347. #endif
  5348.     {
  5349.         if (attr > HL_ALL)                /* special HL attr. */
  5350.         {
  5351.         if (t_colors > 1)
  5352.             aep = syn_cterm_attr2entry(attr);
  5353.         else
  5354.             aep = syn_term_attr2entry(attr);
  5355.         if (aep == NULL)        /* did ":syntax clear" */
  5356.             attr = 0;
  5357.         else
  5358.             attr = aep->ae_attr;
  5359.         }
  5360.         if ((attr & HL_BOLD) && T_MD != NULL)    /* bold */
  5361.         out_str(T_MD);
  5362.         if ((attr & HL_STANDOUT) && T_SO != NULL)    /* standout */
  5363.         out_str(T_SO);
  5364.         if ((attr & HL_UNDERLINE) && T_US != NULL)    /* underline */
  5365.         out_str(T_US);
  5366.         if ((attr & HL_ITALIC) && T_CZH != NULL)    /* italic */
  5367.         out_str(T_CZH);
  5368.         if ((attr & HL_INVERSE) && T_MR != NULL)    /* inverse (reverse) */
  5369.         out_str(T_MR);
  5370.  
  5371.         /*
  5372.          * Output the color or start string after bold etc., in case the
  5373.          * bold etc. override the color setting.
  5374.          */
  5375.         if (aep != NULL)
  5376.         {
  5377.         if (t_colors > 1)
  5378.         {
  5379.             if (aep->ae_u.cterm.fg_color)
  5380.             term_fg_color(aep->ae_u.cterm.fg_color - 1);
  5381.             if (aep->ae_u.cterm.bg_color)
  5382.             term_bg_color(aep->ae_u.cterm.bg_color - 1);
  5383.         }
  5384.         else
  5385.         {
  5386.             if (aep->ae_u.term.start != NULL)
  5387.             out_str(aep->ae_u.term.start);
  5388.         }
  5389.         }
  5390.     }
  5391.     }
  5392. }
  5393.  
  5394.       void
  5395. screen_stop_highlight()
  5396. {
  5397.     int        do_ME = FALSE;        /* output T_ME code */
  5398.  
  5399.     if (screen_attr != 0
  5400. #ifdef WIN3264
  5401.             && termcap_active
  5402. #endif
  5403.                        )
  5404.     {
  5405. #ifdef FEAT_GUI
  5406.     if (gui.in_use)
  5407.     {
  5408.         char    buf[20];
  5409.  
  5410.         /* use internal GUI code */
  5411.         sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
  5412.         OUT_STR(buf);
  5413.     }
  5414.     else
  5415. #endif
  5416.     {
  5417.         if (screen_attr > HL_ALL)            /* special HL attr. */
  5418.         {
  5419.         attrentry_T *aep;
  5420.  
  5421.         if (t_colors > 1)
  5422.         {
  5423.             /*
  5424.              * Assume that t_me restores the original colors!
  5425.              */
  5426.             aep = syn_cterm_attr2entry(screen_attr);
  5427.             if (aep != NULL && (aep->ae_u.cterm.fg_color
  5428.                          || aep->ae_u.cterm.bg_color))
  5429.             do_ME = TRUE;
  5430.         }
  5431.         else
  5432.         {
  5433.             aep = syn_term_attr2entry(screen_attr);
  5434.             if (aep != NULL && aep->ae_u.term.stop != NULL)
  5435.             {
  5436.             if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
  5437.                 do_ME = TRUE;
  5438.             else
  5439.                 out_str(aep->ae_u.term.stop);
  5440.             }
  5441.         }
  5442.         if (aep == NULL)        /* did ":syntax clear" */
  5443.             screen_attr = 0;
  5444.         else
  5445.             screen_attr = aep->ae_attr;
  5446.         }
  5447.  
  5448.         /*
  5449.          * Often all ending-codes are equal to T_ME.  Avoid outputting the
  5450.          * same sequence several times.
  5451.          */
  5452.         if (screen_attr & HL_STANDOUT)
  5453.         {
  5454.         if (STRCMP(T_SE, T_ME) == 0)
  5455.             do_ME = TRUE;
  5456.         else
  5457.             out_str(T_SE);
  5458.         }
  5459.         if (screen_attr & HL_UNDERLINE)
  5460.         {
  5461.         if (STRCMP(T_UE, T_ME) == 0)
  5462.             do_ME = TRUE;
  5463.         else
  5464.             out_str(T_UE);
  5465.         }
  5466.         if (screen_attr & HL_ITALIC)
  5467.         {
  5468.         if (STRCMP(T_CZR, T_ME) == 0)
  5469.             do_ME = TRUE;
  5470.         else
  5471.             out_str(T_CZR);
  5472.         }
  5473.         if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
  5474.         out_str(T_ME);
  5475.  
  5476.         if (t_colors > 1)
  5477.         {
  5478.         /* set Normal cterm colors */
  5479.         if (cterm_normal_fg_color != 0)
  5480.             term_fg_color(cterm_normal_fg_color - 1);
  5481.         if (cterm_normal_bg_color != 0)
  5482.             term_bg_color(cterm_normal_bg_color - 1);
  5483.         if (cterm_normal_fg_bold)
  5484.             out_str(T_MD);
  5485.         }
  5486.     }
  5487.     }
  5488.     screen_attr = 0;
  5489. }
  5490.  
  5491. /*
  5492.  * Reset the colors for a cterm.  Used when leaving Vim.
  5493.  * The machine specific code may override this again.
  5494.  */
  5495.     void
  5496. reset_cterm_colors()
  5497. {
  5498.     if (t_colors > 1)
  5499.     {
  5500.     /* set Normal cterm colors */
  5501.     if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
  5502.     {
  5503.         out_str(T_OP);
  5504.         screen_attr = -1;
  5505.     }
  5506.     if (cterm_normal_fg_bold)
  5507.     {
  5508.         out_str(T_ME);
  5509.         screen_attr = -1;
  5510.     }
  5511.     }
  5512. }
  5513.  
  5514. /*
  5515.  * Put character ScreenLines["off"] on the screen at position "row" and "col",
  5516.  * using the attributes from ScreenAttrs["off"].
  5517.  */
  5518.     static void
  5519. screen_char(off, row, col)
  5520.     unsigned    off;
  5521.     int        row;
  5522.     int        col;
  5523. {
  5524.     int        attr;
  5525.  
  5526.     /* Check for illegal values, just in case (could happen just after
  5527.      * resizing). */
  5528.     if (row >= screen_Rows || col >= screen_Columns)
  5529.     return;
  5530.  
  5531.     /* Outputting the last character on the screen may scrollup the screen.
  5532.      * Don't to it!  Mark the character invalid (update it when scrolled up) */
  5533.     if (row == screen_Rows - 1 && col == screen_Columns - 1)
  5534.     {
  5535.     ScreenAttrs[off] = (sattr_T)-1;
  5536.     return;
  5537.     }
  5538.  
  5539.     /*
  5540.      * Stop highlighting first, so it's easier to move the cursor.
  5541.      */
  5542. #if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT)
  5543.     if (screen_char_attr != 0)
  5544.     attr = screen_char_attr;
  5545.     else
  5546. #endif
  5547.     attr = ScreenAttrs[off];
  5548.     if (screen_attr != attr)
  5549.     screen_stop_highlight();
  5550.  
  5551.     windgoto(row, col);
  5552.  
  5553.     if (screen_attr != attr)
  5554.     screen_start_highlight(attr);
  5555.  
  5556. #ifdef FEAT_MBYTE
  5557.     if (enc_utf8 && ScreenLinesUC[off] != 0)
  5558.     {
  5559.     char_u        buf[MB_MAXBYTES + 1];
  5560.  
  5561.     /* Convert UTF-8 character to bytes and write it. */
  5562.     buf[utfc_char2bytes(off, buf)] = NUL;
  5563.     out_str(buf);
  5564.     if (utf_char2cells(ScreenLinesUC[off]) > 1)
  5565.         ++screen_cur_col;
  5566.     }
  5567.     else
  5568. #endif
  5569.     {
  5570. #ifdef FEAT_MBYTE
  5571.     out_flush_check();
  5572. #endif
  5573.     out_char(ScreenLines[off]);
  5574. #ifdef FEAT_MBYTE
  5575.     /* double-byte character in single-width cell */
  5576.     if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
  5577.         out_char(ScreenLines2[off]);
  5578. #endif
  5579.     }
  5580.  
  5581.     screen_cur_col++;
  5582. }
  5583.  
  5584. #ifdef FEAT_MBYTE
  5585.  
  5586. /*
  5587.  * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
  5588.  * on the screen at position 'row' and 'col'.
  5589.  * The attributes of the first byte is used for all.  This is required to
  5590.  * output the two bytes of a double-byte character with nothing in between.
  5591.  */
  5592.     static void
  5593. screen_char_2(off, row, col)
  5594.     unsigned    off;
  5595.     int        row;
  5596.     int        col;
  5597. {
  5598.     /* Check for illegal values (could be wrong when screen was resized). */
  5599.     if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
  5600.     return;
  5601.  
  5602.     /* Outputting the last character on the screen may scrollup the screen.
  5603.      * Don't to it!  Mark the character invalid (update it when scrolled up) */
  5604.     if (row == screen_Rows - 1 && col >= screen_Columns - 2)
  5605.     {
  5606.     ScreenAttrs[off] = (sattr_T)-1;
  5607.     return;
  5608.     }
  5609.  
  5610.     /* Output the first byte normally (positions the cursor), then write the
  5611.      * second byte directly. */
  5612.     screen_char(off, row, col);
  5613.     out_char(ScreenLines[off + 1]);
  5614.     ++screen_cur_col;
  5615. }
  5616. #endif
  5617.  
  5618. #if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT) || defined(PROTO)
  5619. /*
  5620.  * Draw a rectangle of the screen, inverted when "invert" is TRUE.
  5621.  * This uses the contents of ScreenLines[] and doesn't change it.
  5622.  */
  5623.     void
  5624. screen_draw_rectangle(row, col, height, width, invert)
  5625.     int        row;
  5626.     int        col;
  5627.     int        height;
  5628.     int        width;
  5629.     int        invert;
  5630. {
  5631.     int        r, c;
  5632.     int        off;
  5633.  
  5634.     if (invert)
  5635.     screen_char_attr = HL_INVERSE;
  5636.     for (r = row; r < row + height; ++r)
  5637.     {
  5638.     off = LineOffset[r];
  5639.     for (c = col; c < col + width; ++c)
  5640.     {
  5641. #ifdef FEAT_MBYTE
  5642.         if (enc_dbcs != 0 && dbcs_off2cells(off + c) > 1)
  5643.         {
  5644.         screen_char_2(off + c, r, c);
  5645.         ++c;
  5646.         }
  5647.         else
  5648. #endif
  5649.         {
  5650.         screen_char(off + c, r, c);
  5651. #ifdef FEAT_MBYTE
  5652.         if (utf_off2cells(off + c) > 1)
  5653.             ++c;
  5654. #endif
  5655.         }
  5656.     }
  5657.     }
  5658.     screen_char_attr = 0;
  5659. }
  5660. #endif
  5661.  
  5662. #ifdef FEAT_VERTSPLIT
  5663. /*
  5664.  * Redraw the characters for a vertically split window.
  5665.  */
  5666.     static void
  5667. redraw_block(row, end, wp)
  5668.     int        row;
  5669.     int        end;
  5670.     win_T    *wp;
  5671. {
  5672.     int        col;
  5673.     int        width;
  5674.  
  5675. # ifdef FEAT_CLIPBOARD
  5676.     clip_may_clear_selection(row, end - 1);
  5677. # endif
  5678.  
  5679.     if (wp == NULL)
  5680.     {
  5681.     col = 0;
  5682.     width = Columns;
  5683.     }
  5684.     else
  5685.     {
  5686.     col = wp->w_wincol;
  5687.     width = wp->w_width;
  5688.     }
  5689.     screen_draw_rectangle(row, col, end - row, width, FALSE);
  5690. }
  5691. #endif
  5692.  
  5693. /*
  5694.  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
  5695.  * with character 'c1' in first column followed by 'c2' in the other columns.
  5696.  * Use attributes 'attr'.
  5697.  * Cannot handle multi-byte characters, c1 and c2 must be < 0x80!
  5698.  */
  5699.     void
  5700. screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr)
  5701.     int        start_row, end_row;
  5702.     int        start_col, end_col;
  5703.     int        c1, c2;
  5704.     int        attr;
  5705. {
  5706.     int            row;
  5707.     int            col;
  5708.     int            off;
  5709.     int            end_off;
  5710.     int            did_delete;
  5711.     int            c;
  5712.     int            norm_term;
  5713. #if defined(FEAT_GUI) || defined(UNIX)
  5714.     int            force_next = FALSE;
  5715. #endif
  5716.  
  5717.     if (end_row > screen_Rows)        /* safety check */
  5718.     end_row = screen_Rows;
  5719.     if (end_col > screen_Columns)    /* safety check */
  5720.     end_col = screen_Columns;
  5721.     if (ScreenLines == NULL
  5722.         || start_row >= end_row
  5723.         || start_col >= end_col)    /* nothing to do */
  5724.     return;
  5725.  
  5726.     /* it's a "normal" terminal when not in a GUI or cterm */
  5727.     norm_term = (
  5728. #ifdef FEAT_GUI
  5729.         !gui.in_use &&
  5730. #endif
  5731.                 t_colors <= 1);
  5732.     for (row = start_row; row < end_row; ++row)
  5733.     {
  5734.     /*
  5735.      * Try to use delete-line termcap code, when no attributes or in a
  5736.      * "normal" terminal, where a bold/italic space is just a
  5737.      * space.
  5738.      */
  5739.     did_delete = FALSE;
  5740.     if (c2 == ' '
  5741.         && end_col == Columns
  5742.         && can_clear(T_CE)
  5743.         && (attr == 0
  5744.             || (norm_term
  5745.             && attr <= HL_ALL
  5746.             && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
  5747.     {
  5748.         /*
  5749.          * check if we really need to clear something
  5750.          */
  5751.         col = start_col;
  5752.         if (c1 != ' ')            /* don't clear first char */
  5753.         ++col;
  5754.  
  5755.         off = LineOffset[row] + col;
  5756.         end_off = LineOffset[row] + end_col;
  5757.  
  5758.         /* skip blanks (used often, keep it fast!) */
  5759.         while (off < end_off && ScreenLines[off] == ' '
  5760.                              && ScreenAttrs[off] == 0)
  5761.         ++off;
  5762.         if (off < end_off)        /* something to be cleared */
  5763.         {
  5764.         col = off - LineOffset[row];
  5765.         screen_stop_highlight();
  5766.         term_windgoto(row, col);/* clear rest of this screen line */
  5767.         out_str(T_CE);
  5768.         screen_start();        /* don't know where cursor is now */
  5769.         col = end_col - col;
  5770.         while (col--)        /* clear chars in ScreenLines */
  5771.         {
  5772.             ScreenLines[off] = ' ';
  5773. #ifdef FEAT_MBYTE
  5774.             if (enc_utf8)
  5775.             ScreenLinesUC[off] = 0;
  5776. #endif
  5777.             ScreenAttrs[off] = 0;
  5778.             ++off;
  5779.         }
  5780.         }
  5781.         did_delete = TRUE;        /* the chars are cleared now */
  5782.     }
  5783.  
  5784.     off = LineOffset[row] + start_col;
  5785.     c = c1;
  5786.     for (col = start_col; col < end_col; ++col)
  5787.     {
  5788.         if (ScreenLines[off] != c || ScreenAttrs[off] != attr
  5789. #if defined(FEAT_GUI) || defined(UNIX)
  5790.             || force_next
  5791. #endif
  5792.             )
  5793.         {
  5794. #if defined(FEAT_GUI) || defined(UNIX)
  5795.         /* The bold trick may make a single row of pixels appear in
  5796.          * the next character.  When a bold character is removed, the
  5797.          * next character should be redrawn too.  This happens for our
  5798.          * own GUI and for some xterms.  */
  5799.         if (
  5800. # ifdef FEAT_GUI
  5801.             gui.in_use
  5802. # endif
  5803. # if defined(FEAT_GUI) && defined(UNIX)
  5804.             ||
  5805. # endif
  5806. # ifdef UNIX
  5807.             term_is_xterm
  5808. # endif
  5809.            )
  5810.         {
  5811.             if (ScreenLines[off] != ' '
  5812.                 && (ScreenAttrs[off] > HL_ALL
  5813.                 || ScreenAttrs[off] & HL_BOLD))
  5814.             force_next = TRUE;
  5815.             else
  5816.             force_next = FALSE;
  5817.         }
  5818. #endif
  5819.         ScreenLines[off] = c;
  5820. #ifdef FEAT_MBYTE
  5821.         if (enc_utf8)
  5822.             ScreenLinesUC[off] = 0;
  5823. #endif
  5824.         ScreenAttrs[off] = attr;
  5825.         if (!did_delete || c != ' ')
  5826.             screen_char(off, row, col);
  5827.         }
  5828.         ++off;
  5829.         if (col == start_col)
  5830.         {
  5831.         if (did_delete)
  5832.             break;
  5833.         c = c2;
  5834.         }
  5835.     }
  5836.     if (row == Rows - 1)        /* overwritten the command line */
  5837.     {
  5838.         redraw_cmdline = TRUE;
  5839.         if (c1 == ' ' && c2 == ' ')
  5840.         clear_cmdline = FALSE;    /* command line has been cleared */
  5841.     }
  5842.     }
  5843. }
  5844.  
  5845. /*
  5846.  * Check if there should be a delay.  Used before clearing or redrawing the
  5847.  * screen or the command line.
  5848.  */
  5849.     void
  5850. check_for_delay(check_msg_scroll)
  5851.     int        check_msg_scroll;
  5852. {
  5853.     if ((emsg_on_display || (check_msg_scroll && msg_scroll))
  5854.         && emsg_silent == 0)
  5855.     {
  5856.     out_flush();
  5857.     ui_delay(1000L, TRUE);
  5858.     emsg_on_display = FALSE;
  5859.     if (check_msg_scroll)
  5860.         msg_scroll = FALSE;
  5861.     }
  5862. }
  5863.  
  5864. /*
  5865.  * screen_valid -  allocate screen buffers if size changed
  5866.  *   If "clear" is TRUE: clear screen if it has been resized.
  5867.  *    Returns TRUE if there is a valid screen to write to.
  5868.  *    Returns FALSE when starting up and screen not initialized yet.
  5869.  */
  5870.     int
  5871. screen_valid(clear)
  5872.     int        clear;
  5873. {
  5874.     screenalloc(clear);        /* allocate screen buffers if size changed */
  5875.     return (ScreenLines != NULL);
  5876. }
  5877.  
  5878. /*
  5879.  * Resize the shell to Rows and Columns.
  5880.  * Allocate ScreenLines[] and associated items.
  5881.  *
  5882.  * There may be some time between setting Rows and Columns and (re)allocating
  5883.  * ScreenLines[].  This happens when starting up and when (manually) changing
  5884.  * the shell size.  Always use screen_Rows and screen_Columns to access items
  5885.  * in ScreenLines[].  Use Rows and Columns for positioning text etc. where the
  5886.  * final size of the shell is needed.
  5887.  */
  5888.     void
  5889. screenalloc(clear)
  5890.     int        clear;
  5891. {
  5892.     int            new_row, old_row;
  5893. #ifdef FEAT_GUI
  5894.     int            old_Rows;
  5895. #endif
  5896.     win_T        *wp;
  5897.     int            outofmem = FALSE;
  5898.     int            len;
  5899.     schar_T        *new_ScreenLines;
  5900. #ifdef FEAT_MBYTE
  5901.     u8char_T        *new_ScreenLinesUC = NULL;
  5902.     u8char_T        *new_ScreenLinesC1 = NULL;
  5903.     u8char_T        *new_ScreenLinesC2 = NULL;
  5904.     schar_T        *new_ScreenLines2 = NULL;
  5905. #endif
  5906.     sattr_T        *new_ScreenAttrs;
  5907.     unsigned        *new_LineOffset;
  5908.     static int        entered = FALSE;        /* avoid recursiveness */
  5909.  
  5910.     /*
  5911.      * Allocation of the screen buffers is done only when the size changes and
  5912.      * when Rows and Columns have been set and we have started doing full
  5913.      * screen stuff.
  5914.      */
  5915.     if ((ScreenLines != NULL
  5916.         && Rows == screen_Rows
  5917.         && Columns == screen_Columns
  5918. #ifdef FEAT_MBYTE
  5919.         && enc_utf8 == (ScreenLinesUC != NULL)
  5920.         && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
  5921. #endif
  5922.         )
  5923.         || Rows == 0
  5924.         || Columns == 0
  5925.         || (!full_screen && ScreenLines == NULL))
  5926.     return;
  5927.  
  5928.     /*
  5929.      * It's possible that we produce an out-of-memory message below, which
  5930.      * will cause this function to be called again.  To break the loop, just
  5931.      * return here.
  5932.      */
  5933.     if (entered)
  5934.     return;
  5935.     entered = TRUE;
  5936.  
  5937. #ifdef FEAT_GUI_BEOS
  5938.     vim_lock_screen();  /* be safe, put it here */
  5939. #endif
  5940.  
  5941.     comp_col();        /* recompute columns for shown command and ruler */
  5942.  
  5943.     /*
  5944.      * We're changing the size of the screen.
  5945.      * - Allocate new arrays for ScreenLines and ScreenAttrs.
  5946.      * - Move lines from the old arrays into the new arrays, clear extra
  5947.      *     lines (unless the screen is going to be cleared).
  5948.      * - Free the old arrays.
  5949.      *
  5950.      * If anything fails, make ScreenLines NULL, so we don't do anything!
  5951.      * Continuing with the old ScreenLines may result in a crash, because the
  5952.      * size is wrong.
  5953.      */
  5954. #ifdef FEAT_WINDOWS
  5955.     for (wp = firstwin; wp; wp = wp->w_next)
  5956.     win_free_lsize(wp);
  5957. #else
  5958.     win_free_lsize(curwin);
  5959. #endif
  5960.  
  5961.     new_ScreenLines = (schar_T *)lalloc((long_u)(
  5962.                   (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
  5963. #ifdef FEAT_MBYTE
  5964.     if (enc_utf8)
  5965.     {
  5966.     new_ScreenLinesUC = (u8char_T *)lalloc((long_u)(
  5967.                  (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
  5968.     new_ScreenLinesC1 = (u8char_T *)lalloc((long_u)(
  5969.                  (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
  5970.     new_ScreenLinesC2 = (u8char_T *)lalloc((long_u)(
  5971.                  (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
  5972.     }
  5973.     if (enc_dbcs == DBCS_JPNU)
  5974.     new_ScreenLines2 = (schar_T *)lalloc((long_u)(
  5975.                  (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
  5976. #endif
  5977.     new_ScreenAttrs = (sattr_T *)lalloc((long_u)(
  5978.                   (Rows + 1) * Columns * sizeof(sattr_T)), FALSE);
  5979.     new_LineOffset = (unsigned *)lalloc((long_u)(
  5980.                      Rows * sizeof(unsigned)), FALSE);
  5981.  
  5982.     FOR_ALL_WINDOWS(wp)
  5983.     {
  5984.     if (win_alloc_lines(wp) == FAIL)
  5985.     {
  5986.         outofmem = TRUE;
  5987. #ifdef FEAT_WINDOWS
  5988.         break;
  5989. #endif
  5990.     }
  5991.     }
  5992.  
  5993.     if (new_ScreenLines == NULL
  5994. #ifdef FEAT_MBYTE
  5995.         || (enc_utf8 && (new_ScreenLinesUC == NULL
  5996.            || new_ScreenLinesC1 == NULL || new_ScreenLinesC2 == NULL))
  5997.         || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
  5998. #endif
  5999.         || new_ScreenAttrs == NULL
  6000.         || new_LineOffset == NULL
  6001.         || outofmem)
  6002.     {
  6003.     do_outofmem_msg((long_u)((Rows + 1) * Columns));    /* guess the size */
  6004.     vim_free(new_ScreenLines);
  6005.     new_ScreenLines = NULL;
  6006. #ifdef FEAT_MBYTE
  6007.     vim_free(new_ScreenLinesUC);
  6008.     new_ScreenLinesUC = NULL;
  6009.     vim_free(new_ScreenLinesC1);
  6010.     new_ScreenLinesC1 = NULL;
  6011.     vim_free(new_ScreenLinesC2);
  6012.     new_ScreenLinesC2 = NULL;
  6013.     vim_free(new_ScreenLines2);
  6014.     new_ScreenLines2 = NULL;
  6015. #endif
  6016.     vim_free(new_ScreenAttrs);
  6017.     new_ScreenAttrs = NULL;
  6018.     vim_free(new_LineOffset);
  6019.     new_LineOffset = NULL;
  6020.     }
  6021.     else
  6022.     {
  6023.     for (new_row = 0; new_row < Rows; ++new_row)
  6024.     {
  6025.         new_LineOffset[new_row] = new_row * Columns;
  6026.  
  6027.         /*
  6028.          * If the screen is not going to be cleared, copy as much as
  6029.          * possible from the old screen to the new one and clear the rest
  6030.          * (used when resizing the window at the "--more--" prompt or when
  6031.          * executing an external command, for the GUI).
  6032.          */
  6033.         if (!clear)
  6034.         {
  6035.         (void)vim_memset(new_ScreenLines + new_row * Columns,
  6036.                       ' ', (size_t)Columns * sizeof(schar_T));
  6037. #ifdef FEAT_MBYTE
  6038.         if (enc_utf8)
  6039.         {
  6040.             (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
  6041.                        0, (size_t)Columns * sizeof(u8char_T));
  6042.             (void)vim_memset(new_ScreenLinesC1 + new_row * Columns,
  6043.                        0, (size_t)Columns * sizeof(u8char_T));
  6044.             (void)vim_memset(new_ScreenLinesC2 + new_row * Columns,
  6045.                        0, (size_t)Columns * sizeof(u8char_T));
  6046.         }
  6047.         if (enc_dbcs == DBCS_JPNU)
  6048.             (void)vim_memset(new_ScreenLines2 + new_row * Columns,
  6049.                        0, (size_t)Columns * sizeof(schar_T));
  6050. #endif
  6051.         (void)vim_memset(new_ScreenAttrs + new_row * Columns,
  6052.                     0, (size_t)Columns * sizeof(sattr_T));
  6053.         old_row = new_row + (screen_Rows - Rows);
  6054.         if (old_row >= 0)
  6055.         {
  6056.             if (screen_Columns < Columns)
  6057.             len = screen_Columns;
  6058.             else
  6059.             len = Columns;
  6060.             mch_memmove(new_ScreenLines + new_LineOffset[new_row],
  6061.                 ScreenLines + LineOffset[old_row],
  6062.                 (size_t)len * sizeof(schar_T));
  6063. #ifdef FEAT_MBYTE
  6064.             if (enc_utf8 && ScreenLinesUC != NULL)
  6065.             {
  6066.             mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
  6067.                 ScreenLinesUC + LineOffset[old_row],
  6068.                 (size_t)len * sizeof(u8char_T));
  6069.             mch_memmove(new_ScreenLinesC1 + new_LineOffset[new_row],
  6070.                 ScreenLinesC1 + LineOffset[old_row],
  6071.                 (size_t)len * sizeof(u8char_T));
  6072.             mch_memmove(new_ScreenLinesC2 + new_LineOffset[new_row],
  6073.                 ScreenLinesC2 + LineOffset[old_row],
  6074.                 (size_t)len * sizeof(u8char_T));
  6075.             }
  6076.             if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
  6077.             mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
  6078.                 ScreenLines2 + LineOffset[old_row],
  6079.                 (size_t)len * sizeof(schar_T));
  6080. #endif
  6081.             mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
  6082.                 ScreenAttrs + LineOffset[old_row],
  6083.                 (size_t)len * sizeof(sattr_T));
  6084.         }
  6085.         }
  6086.     }
  6087.     /* Use the last line of the screen for the current line. */
  6088.     current_ScreenLine = new_ScreenLines + Rows * Columns;
  6089.     }
  6090.  
  6091.     vim_free(ScreenLines);
  6092. #ifdef FEAT_MBYTE
  6093.     vim_free(ScreenLinesUC);
  6094.     vim_free(ScreenLinesC1);
  6095.     vim_free(ScreenLinesC2);
  6096.     vim_free(ScreenLines2);
  6097. #endif
  6098.     vim_free(ScreenAttrs);
  6099.     vim_free(LineOffset);
  6100.     ScreenLines = new_ScreenLines;
  6101. #ifdef FEAT_MBYTE
  6102.     ScreenLinesUC = new_ScreenLinesUC;
  6103.     ScreenLinesC1 = new_ScreenLinesC1;
  6104.     ScreenLinesC2 = new_ScreenLinesC2;
  6105.     ScreenLines2 = new_ScreenLines2;
  6106. #endif
  6107.     ScreenAttrs = new_ScreenAttrs;
  6108.     LineOffset = new_LineOffset;
  6109.  
  6110.     /* It's important that screen_Rows and screen_Columns reflect the actual
  6111.      * size of ScreenLines[].  Set them before calling anything. */
  6112. #ifdef FEAT_GUI
  6113.     old_Rows = screen_Rows;
  6114. #endif
  6115.     screen_Rows = Rows;
  6116.     screen_Columns = Columns;
  6117.  
  6118.     must_redraw = CLEAR;    /* need to clear the screen later */
  6119.     if (clear)
  6120.     screenclear2();
  6121.  
  6122. #ifdef FEAT_GUI
  6123.     else if (gui.in_use
  6124.         && !gui.starting
  6125.         && ScreenLines != NULL
  6126.         && old_Rows != Rows)
  6127.     {
  6128.     (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
  6129.     /*
  6130.      * Adjust the position of the cursor, for when executing an external
  6131.      * command.
  6132.      */
  6133.     if (msg_row >= Rows)        /* Rows got smaller */
  6134.         msg_row = Rows - 1;        /* put cursor at last row */
  6135.     else if (Rows > old_Rows)    /* Rows got bigger */
  6136.         msg_row += Rows - old_Rows; /* put cursor in same place */
  6137.     if (msg_col >= Columns)        /* Columns got smaller */
  6138.         msg_col = Columns - 1;    /* put cursor at last column */
  6139.     }
  6140. #endif
  6141.  
  6142. #ifdef FEAT_GUI_BEOS
  6143.     vim_unlock_screen();
  6144. #endif
  6145.     entered = FALSE;
  6146. }
  6147.  
  6148.     void
  6149. screenclear()
  6150. {
  6151.     check_for_delay(FALSE);
  6152.     screenalloc(FALSE);        /* allocate screen buffers if size changed */
  6153.     screenclear2();        /* clear the screen */
  6154. }
  6155.  
  6156.     static void
  6157. screenclear2()
  6158. {
  6159.     int        i;
  6160.  
  6161.     if (starting == NO_SCREEN || ScreenLines == NULL)
  6162.     return;
  6163.  
  6164. #ifdef FEAT_GUI
  6165.     if (!gui.in_use)
  6166. #endif
  6167.     screen_attr = -1;    /* force setting the Normal colors */
  6168.     screen_stop_highlight();    /* don't want highlighting here */
  6169.  
  6170. #ifdef FEAT_CLIPBOARD
  6171.     /* disable selection without redrawing it */
  6172.     clip_scroll_selection(9999);
  6173. #endif
  6174.  
  6175.     /* blank out ScreenLines */
  6176.     for (i = 0; i < Rows; ++i)
  6177.     lineclear(LineOffset[i], (int)Columns);
  6178.  
  6179.     if (can_clear(T_CL))
  6180.     {
  6181.     out_str(T_CL);        /* clear the display */
  6182.     clear_cmdline = FALSE;
  6183.     }
  6184.     else
  6185.     {
  6186.     /* can't clear the screen, mark all chars with invalid attributes */
  6187.     for (i = 0; i < Rows; ++i)
  6188.         lineinvalid(LineOffset[i], (int)Columns);
  6189.     clear_cmdline = TRUE;
  6190.     }
  6191.  
  6192.     screen_cleared = TRUE;    /* can use contents of ScreenLines now */
  6193.  
  6194.     win_rest_invalid(firstwin);
  6195.     redraw_cmdline = TRUE;
  6196.     if (must_redraw == CLEAR)    /* no need to clear again */
  6197.     must_redraw = NOT_VALID;
  6198.     compute_cmdrow();
  6199.     msg_row = cmdline_row;    /* put cursor on last line for messages */
  6200.     msg_col = 0;
  6201.     screen_start();        /* don't know where cursor is now */
  6202.     msg_scrolled = 0;        /* can't scroll back */
  6203.     msg_didany = FALSE;
  6204.     msg_didout = FALSE;
  6205. }
  6206.  
  6207. /*
  6208.  * Clear one line in ScreenLines.
  6209.  */
  6210.     static void
  6211. lineclear(off, width)
  6212.     unsigned    off;
  6213.     int        width;
  6214. {
  6215.     (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
  6216. #ifdef FEAT_MBYTE
  6217.     if (enc_utf8)
  6218.     (void)vim_memset(ScreenLinesUC + off, 0,
  6219.                       (size_t)width * sizeof(u8char_T));
  6220. #endif
  6221.     (void)vim_memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
  6222. }
  6223.  
  6224. /*
  6225.  * Mark one line in ScreenLines invalid by setting the attributes to an
  6226.  * invalid value.
  6227.  */
  6228.     static void
  6229. lineinvalid(off, width)
  6230.     unsigned    off;
  6231.     int        width;
  6232. {
  6233.     (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
  6234. }
  6235.  
  6236. #ifdef FEAT_VERTSPLIT
  6237. /*
  6238.  * Copy part of a Screenline for vertically split window "wp".
  6239.  */
  6240.     static void
  6241. linecopy(to, from, wp)
  6242.     int        to;
  6243.     int        from;
  6244.     win_T    *wp;
  6245. {
  6246.     unsigned    off_to = LineOffset[to] + wp->w_wincol;
  6247.     unsigned    off_from = LineOffset[from] + wp->w_wincol;
  6248.  
  6249.     mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
  6250.         wp->w_width * sizeof(schar_T));
  6251. # ifdef FEAT_MBYTE
  6252.     if (enc_utf8)
  6253.     {
  6254.     mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
  6255.         wp->w_width * sizeof(u8char_T));
  6256.     mch_memmove(ScreenLinesC1 + off_to, ScreenLinesC1 + off_from,
  6257.         wp->w_width * sizeof(u8char_T));
  6258.     mch_memmove(ScreenLinesC2 + off_to, ScreenLinesC2 + off_from,
  6259.         wp->w_width * sizeof(u8char_T));
  6260.     }
  6261.     if (enc_dbcs == DBCS_JPNU)
  6262.     mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
  6263.         wp->w_width * sizeof(schar_T));
  6264. # endif
  6265.     mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
  6266.         wp->w_width * sizeof(sattr_T));
  6267. }
  6268. #endif
  6269.  
  6270. /*
  6271.  * Return TRUE if clearing with term string "p" would work.
  6272.  * It can't work when the string is empty or it won't set the right background.
  6273.  */
  6274.     int
  6275. can_clear(p)
  6276.     char_u    *p;
  6277. {
  6278.     return (*p != NUL && (t_colors <= 1
  6279. #ifdef FEAT_GUI
  6280.         || gui.in_use
  6281. #endif
  6282.         || cterm_normal_bg_color == 0 || *T_UT != NUL));
  6283. }
  6284.  
  6285. /*
  6286.  * Reset cursor position. Use whenever cursor was moved because of outputting
  6287.  * something directly to the screen (shell commands) or a terminal control
  6288.  * code.
  6289.  */
  6290.     void
  6291. screen_start()
  6292. {
  6293.     screen_cur_row = screen_cur_col = 9999;
  6294. }
  6295.  
  6296. /*
  6297.  * Note that the cursor has gone down to the next line, column 0.
  6298.  * Used for Ex mode.
  6299.  */
  6300.     void
  6301. screen_down()
  6302. {
  6303.     screen_cur_col = 0;
  6304.     if (screen_cur_row < Rows - 1)
  6305.     ++screen_cur_row;
  6306. }
  6307.  
  6308. /*
  6309.  * Move the cursor to position "row","col" in the screen.
  6310.  * This tries to find the most efficient way to move, minimizing the number of
  6311.  * characters sent to the terminal.
  6312.  */
  6313.     void
  6314. windgoto(row, col)
  6315.     int        row;
  6316.     int        col;
  6317. {
  6318.     char_u        *p;
  6319.     int            i;
  6320.     int            plan;
  6321.     int            cost;
  6322.     int            wouldbe_col;
  6323.     int            noinvcurs;
  6324.     char_u        *bs;
  6325.     int            goto_cost;
  6326.     int            attr;
  6327.  
  6328. #define GOTO_COST   7    /* asssume a term_windgoto() takes about 7 chars */
  6329. #define HIGHL_COST  5    /* assume unhighlight takes 5 chars */
  6330.  
  6331. #define PLAN_LE        1
  6332. #define PLAN_CR        2
  6333. #define PLAN_NL        3
  6334. #define PLAN_WRITE  4
  6335.     /* Can't use ScreenLines unless initialized */
  6336.     if (ScreenLines == NULL)
  6337.     return;
  6338.  
  6339.     if (col != screen_cur_col || row != screen_cur_row)
  6340.     {
  6341.     /* Check for valid position. */
  6342.     if (row < 0)    /* window without text lines? */
  6343.         row = 0;
  6344.     if (row >= screen_Rows)
  6345.         row = screen_Rows - 1;
  6346.     if (col >= screen_Columns)
  6347.         col = screen_Columns - 1;
  6348.  
  6349.     /* check if no cursor movement is allowed in highlight mode */
  6350.     if (screen_attr && *T_MS == NUL)
  6351.         noinvcurs = HIGHL_COST;
  6352.     else
  6353.         noinvcurs = 0;
  6354.     goto_cost = GOTO_COST + noinvcurs;
  6355.  
  6356.     /*
  6357.      * Plan how to do the positioning:
  6358.      * 1. Use CR to move it to column 0, same row.
  6359.      * 2. Use T_LE to move it a few columns to the left.
  6360.      * 3. Use NL to move a few lines down, column 0.
  6361.      * 4. Move a few columns to the right with T_ND or by writing chars.
  6362.      *
  6363.      * Don't do this if the cursor went beyond the last column, the cursor
  6364.      * position is unknown then (some terminals wrap, some don't )
  6365.      *
  6366.      * First check if the highlighting attibutes allow us to write
  6367.      * characters to move the cursor to the right.
  6368.      */
  6369.     if (row >= screen_cur_row && screen_cur_col < Columns)
  6370.     {
  6371.         /*
  6372.          * If the cursor is in the same row, bigger col, we can use CR
  6373.          * or T_LE.
  6374.          */
  6375.         bs = NULL;                /* init for GCC */
  6376.         attr = screen_attr;
  6377.         if (row == screen_cur_row && col < screen_cur_col)
  6378.         {
  6379.         /* "le" is preferred over "bc", because "bc" is obsolete */
  6380.         if (*T_LE)
  6381.             bs = T_LE;            /* "cursor left" */
  6382.         else
  6383.             bs = T_BC;            /* "backspace character (old) */
  6384.         if (*bs)
  6385.             cost = (screen_cur_col - col) * (int)STRLEN(bs);
  6386.         else
  6387.             cost = 999;
  6388.         if (col + 1 < cost)        /* using CR is less characters */
  6389.         {
  6390.             plan = PLAN_CR;
  6391.             wouldbe_col = 0;
  6392.             cost = 1;            /* CR is just one character */
  6393.         }
  6394.         else
  6395.         {
  6396.             plan = PLAN_LE;
  6397.             wouldbe_col = col;
  6398.         }
  6399.         if (noinvcurs)            /* will stop highlighting */
  6400.         {
  6401.             cost += noinvcurs;
  6402.             attr = 0;
  6403.         }
  6404.         }
  6405.  
  6406.         /*
  6407.          * If the cursor is above where we want to be, we can use CR LF.
  6408.          */
  6409.         else if (row > screen_cur_row)
  6410.         {
  6411.         plan = PLAN_NL;
  6412.         wouldbe_col = 0;
  6413.         cost = (row - screen_cur_row) * 2;  /* CR LF */
  6414.         if (noinvcurs)            /* will stop highlighting */
  6415.         {
  6416.             cost += noinvcurs;
  6417.             attr = 0;
  6418.         }
  6419.         }
  6420.  
  6421.         /*
  6422.          * If the cursor is in the same row, smaller col, just use write.
  6423.          */
  6424.         else
  6425.         {
  6426.         plan = PLAN_WRITE;
  6427.         wouldbe_col = screen_cur_col;
  6428.         cost = 0;
  6429.         }
  6430.  
  6431.         /*
  6432.          * Check if any characters that need to be written have the
  6433.          * correct attributes.  Also avoid UTF-8 characters.
  6434.          */
  6435.         i = col - wouldbe_col;
  6436.         if (i > 0)
  6437.         cost += i;
  6438.         if (cost < goto_cost && i > 0)
  6439.         {
  6440.         /*
  6441.          * Check if the attributes are correct without additionally
  6442.          * stopping highlighting.
  6443.          */
  6444.         p = ScreenAttrs + LineOffset[row] + wouldbe_col;
  6445.         while (i && *p++ == attr)
  6446.             --i;
  6447.         if (i != 0)
  6448.         {
  6449.             /*
  6450.              * Try if it works when highlighting is stopped here.
  6451.              */
  6452.             if (*--p == 0)
  6453.             {
  6454.             cost += noinvcurs;
  6455.             while (i && *p++ == 0)
  6456.                 --i;
  6457.             }
  6458.             if (i != 0)
  6459.             cost = 999;    /* different attributes, don't do it */
  6460.         }
  6461. #ifdef FEAT_MBYTE
  6462.         if (enc_utf8)
  6463.         {
  6464.             /* Don't use an UTF-8 char for positioning, it's slow. */
  6465.             i = col - wouldbe_col;
  6466.             p = ScreenLines + LineOffset[row] + wouldbe_col;
  6467.             while (i && MB_BYTE2LEN(*p++) == 1)
  6468.             --i;
  6469.             if (i != 0)
  6470.             cost = 999;
  6471.         }
  6472. #endif
  6473.         }
  6474.  
  6475.         /*
  6476.          * We can do it without term_windgoto()!
  6477.          */
  6478.         if (cost < goto_cost)
  6479.         {
  6480.         if (plan == PLAN_LE)
  6481.         {
  6482.             if (noinvcurs)
  6483.             screen_stop_highlight();
  6484.             while (screen_cur_col > col)
  6485.             {
  6486.             out_str(bs);
  6487.             --screen_cur_col;
  6488.             }
  6489.         }
  6490.         else if (plan == PLAN_CR)
  6491.         {
  6492.             if (noinvcurs)
  6493.             screen_stop_highlight();
  6494.             out_char('\r');
  6495.             screen_cur_col = 0;
  6496.         }
  6497.         else if (plan == PLAN_NL)
  6498.         {
  6499.             if (noinvcurs)
  6500.             screen_stop_highlight();
  6501.             while (screen_cur_row < row)
  6502.             {
  6503.             out_char('\n');
  6504.             ++screen_cur_row;
  6505.             }
  6506.             screen_cur_col = 0;
  6507.         }
  6508.  
  6509.         i = col - screen_cur_col;
  6510.         if (i > 0)
  6511.         {
  6512.             /*
  6513.              * Use cursor-right if it's one character only.  Avoids
  6514.              * removing a line of pixels from the last bold char, when
  6515.              * using the bold trick in the GUI.
  6516.              */
  6517.             if (T_ND[0] != NUL && T_ND[1] == NUL)
  6518.             {
  6519.             while (i-- > 0)
  6520.                 out_char(*T_ND);
  6521.             }
  6522.             else
  6523.             {
  6524.             int    off;
  6525.  
  6526.             off = LineOffset[row] + screen_cur_col;
  6527.             while (i-- > 0)
  6528.             {
  6529.                 if (ScreenAttrs[off] != screen_attr)
  6530.                 screen_stop_highlight();
  6531. #ifdef FEAT_MBYTE
  6532.                 out_flush_check();
  6533. #endif
  6534.                 out_char(ScreenLines[off]);
  6535. #ifdef FEAT_MBYTE
  6536.                 if (enc_dbcs == DBCS_JPNU
  6537.                           && ScreenLines[off] == 0x8e)
  6538.                 out_char(ScreenLines2[off]);
  6539. #endif
  6540.                 ++off;
  6541.             }
  6542.             }
  6543.         }
  6544.         }
  6545.     }
  6546.     else
  6547.         cost = 999;
  6548.  
  6549.     if (cost >= goto_cost)
  6550.     {
  6551.         if (noinvcurs)
  6552.         screen_stop_highlight();
  6553.         if (row == screen_cur_row && (col > screen_cur_col) &&
  6554.                                 *T_CRI != NUL)
  6555.         term_cursor_right(col - screen_cur_col);
  6556.         else
  6557.         term_windgoto(row, col);
  6558.     }
  6559.     screen_cur_row = row;
  6560.     screen_cur_col = col;
  6561.     }
  6562. }
  6563.  
  6564. /*
  6565.  * Set cursor to its position in the current window.
  6566.  */
  6567.     void
  6568. setcursor()
  6569. {
  6570.     if (redrawing())
  6571.     {
  6572.     validate_cursor();
  6573.     windgoto(W_WINROW(curwin) + curwin->w_wrow,
  6574.         W_WINCOL(curwin) + (
  6575. #ifdef FEAT_RIGHTLEFT
  6576.         curwin->w_p_rl ? ((int)W_WIDTH(curwin) - curwin->w_wcol - (
  6577. # ifdef FEAT_MBYTE
  6578.             has_mbyte ? (*mb_ptr2cells)(ml_get_cursor()) :
  6579. # endif
  6580.             1)) :
  6581. #endif
  6582.                                 curwin->w_wcol));
  6583.     }
  6584. }
  6585.  
  6586.  
  6587. /*
  6588.  * insert 'line_count' lines at 'row' in window 'wp'
  6589.  * if 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
  6590.  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
  6591.  * scrolling.
  6592.  * Returns FAIL if the lines are not inserted, OK for success.
  6593.  */
  6594.     int
  6595. win_ins_lines(wp, row, line_count, invalid, mayclear)
  6596.     win_T    *wp;
  6597.     int        row;
  6598.     int        line_count;
  6599.     int        invalid;
  6600.     int        mayclear;
  6601. {
  6602.     int        did_delete;
  6603.     int        nextrow;
  6604.     int        lastrow;
  6605.     int        retval;
  6606.  
  6607.     if (invalid)
  6608.     wp->w_lines_valid = 0;
  6609.  
  6610.     if (wp->w_height < 5)
  6611.     return FAIL;
  6612.  
  6613.     if (line_count > wp->w_height - row)
  6614.     line_count = wp->w_height - row;
  6615.  
  6616.     retval = win_do_lines(wp, row, line_count, mayclear, FALSE);
  6617.     if (retval != MAYBE)
  6618.     return retval;
  6619.  
  6620.     /*
  6621.      * If there is a next window or a status line, we first try to delete the
  6622.      * lines at the bottom to avoid messing what is after the window.
  6623.      * If this fails and there are following windows, don't do anything to avoid
  6624.      * messing up those windows, better just redraw.
  6625.      */
  6626.     did_delete = FALSE;
  6627. #ifdef FEAT_WINDOWS
  6628.     if (wp->w_next != NULL || wp->w_status_height)
  6629.     {
  6630.     if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
  6631.                     line_count, (int)Rows, FALSE, NULL) == OK)
  6632.         did_delete = TRUE;
  6633.     else if (wp->w_next)
  6634.         return FAIL;
  6635.     }
  6636. #endif
  6637.     /*
  6638.      * if no lines deleted, blank the lines that will end up below the window
  6639.      */
  6640.     if (!did_delete)
  6641.     {
  6642. #ifdef FEAT_WINDOWS
  6643.     wp->w_redr_status = TRUE;
  6644. #endif
  6645.     redraw_cmdline = TRUE;
  6646.     nextrow = W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp);
  6647.     lastrow = nextrow + line_count;
  6648.     if (lastrow > Rows)
  6649.         lastrow = Rows;
  6650.     screen_fill(nextrow - line_count, lastrow - line_count,
  6651.           W_WINCOL(wp), (int)W_ENDCOL(wp),
  6652.           ' ', ' ', 0);
  6653.     }
  6654.  
  6655.     if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, NULL)
  6656.                                       == FAIL)
  6657.     {
  6658.         /* deletion will have messed up other windows */
  6659.     if (did_delete)
  6660.     {
  6661. #ifdef FEAT_WINDOWS
  6662.         wp->w_redr_status = TRUE;
  6663. #endif
  6664.         win_rest_invalid(W_NEXT(wp));
  6665.     }
  6666.     return FAIL;
  6667.     }
  6668.  
  6669.     return OK;
  6670. }
  6671.  
  6672. /*
  6673.  * delete "line_count" window lines at "row" in window "wp"
  6674.  * If "invalid" is TRUE curwin->w_lines[] is invalidated.
  6675.  * If "mayclear" is TRUE the screen will be cleared if it is faster than
  6676.  * scrolling
  6677.  * Return OK for success, FAIL if the lines are not deleted.
  6678.  */
  6679.     int
  6680. win_del_lines(wp, row, line_count, invalid, mayclear)
  6681.     win_T    *wp;
  6682.     int        row;
  6683.     int        line_count;
  6684.     int        invalid;
  6685.     int        mayclear;
  6686. {
  6687.     int        retval;
  6688.  
  6689.     if (invalid)
  6690.     wp->w_lines_valid = 0;
  6691.  
  6692.     if (line_count > wp->w_height - row)
  6693.     line_count = wp->w_height - row;
  6694.  
  6695.     retval = win_do_lines(wp, row, line_count, mayclear, TRUE);
  6696.     if (retval != MAYBE)
  6697.     return retval;
  6698.  
  6699.     if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
  6700.                           (int)Rows, FALSE, NULL) == FAIL)
  6701.     return FAIL;
  6702.  
  6703. #ifdef FEAT_WINDOWS
  6704.     /*
  6705.      * If there are windows or status lines below, try to put them at the
  6706.      * correct place. If we can't do that, they have to be redrawn.
  6707.      */
  6708.     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
  6709.     {
  6710.     if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
  6711.                      line_count, (int)Rows, NULL) == FAIL)
  6712.     {
  6713.         wp->w_redr_status = TRUE;
  6714.         win_rest_invalid(wp->w_next);
  6715.     }
  6716.     }
  6717.     /*
  6718.      * If this is the last window and there is no status line, redraw the
  6719.      * command line later.
  6720.      */
  6721.     else
  6722. #endif
  6723.     redraw_cmdline = TRUE;
  6724.     return OK;
  6725. }
  6726.  
  6727. /*
  6728.  * Common code for win_ins_lines() and win_del_lines().
  6729.  * Returns OK or FAIL when the work has been done.
  6730.  * Returns MAYBE when not finished yet.
  6731.  */
  6732.     static int
  6733. win_do_lines(wp, row, line_count, mayclear, del)
  6734.     win_T    *wp;
  6735.     int        row;
  6736.     int        line_count;
  6737.     int        mayclear;
  6738.     int        del;
  6739. {
  6740.     int        retval;
  6741.  
  6742.     if (!redrawing() || line_count <= 0)
  6743.     return FAIL;
  6744.  
  6745.     /* only a few lines left: redraw is faster */
  6746.     if (mayclear && Rows - line_count < 5
  6747. #ifdef FEAT_VERTSPLIT
  6748.         && wp->w_width == Columns
  6749. #endif
  6750.         )
  6751.     {
  6752.     screenclear();        /* will set wp->w_lines_valid to 0 */
  6753.     return FAIL;
  6754.     }
  6755.  
  6756.     /*
  6757.      * Delete all remaining lines
  6758.      */
  6759.     if (row + line_count >= wp->w_height)
  6760.     {
  6761.     screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
  6762.         W_WINCOL(wp), (int)W_ENDCOL(wp),
  6763.         ' ', ' ', 0);
  6764.     return OK;
  6765.     }
  6766.  
  6767.     /*
  6768.      * when scrolling, the message on the command line should be cleared,
  6769.      * otherwise it will stay there forever.
  6770.      */
  6771.     clear_cmdline = TRUE;
  6772.  
  6773.     /*
  6774.      * If the terminal can set a scroll region, use that.
  6775.      * Always do this in a vertically split window.  This will redraw from
  6776.      * ScreenLines[] when t_CV isn't defined.  That's faster than using
  6777.      * win_line().
  6778.      * Don't use a scroll region when we are going to redraw the text, writing
  6779.      * a character in the lower right corner of the scroll region causes a
  6780.      * scroll-up in the DJGPP version.
  6781.      */
  6782.     if (scroll_region
  6783. #ifdef FEAT_VERTSPLIT
  6784.         || W_WIDTH(wp) != Columns
  6785. #endif
  6786.         )
  6787.     {
  6788. #ifdef FEAT_VERTSPLIT
  6789.     if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
  6790. #endif
  6791.         scroll_region_set(wp, row);
  6792.     if (del)
  6793.         retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
  6794.                            wp->w_height - row, FALSE, wp);
  6795.     else
  6796.         retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
  6797.                               wp->w_height - row, wp);
  6798. #ifdef FEAT_VERTSPLIT
  6799.     if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
  6800. #endif
  6801.         scroll_region_reset();
  6802.     return retval;
  6803.     }
  6804.  
  6805. #ifdef FEAT_WINDOWS
  6806.     if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
  6807.     return FAIL;
  6808. #endif
  6809.  
  6810.     return MAYBE;
  6811. }
  6812.  
  6813. /*
  6814.  * window 'wp' and everything after it is messed up, mark it for redraw
  6815.  */
  6816.     static void
  6817. win_rest_invalid(wp)
  6818.     win_T    *wp;
  6819. {
  6820. #ifdef FEAT_WINDOWS
  6821.     while (wp != NULL)
  6822. #else
  6823.     if (wp != NULL)
  6824. #endif
  6825.     {
  6826.     redraw_win_later(wp, NOT_VALID);
  6827. #ifdef FEAT_WINDOWS
  6828.     wp->w_redr_status = TRUE;
  6829.     wp = wp->w_next;
  6830. #endif
  6831.     }
  6832.     redraw_cmdline = TRUE;
  6833. }
  6834.  
  6835. /*
  6836.  * The rest of the routines in this file perform screen manipulations. The
  6837.  * given operation is performed physically on the screen. The corresponding
  6838.  * change is also made to the internal screen image. In this way, the editor
  6839.  * anticipates the effect of editing changes on the appearance of the screen.
  6840.  * That way, when we call screenupdate a complete redraw isn't usually
  6841.  * necessary. Another advantage is that we can keep adding code to anticipate
  6842.  * screen changes, and in the meantime, everything still works.
  6843.  */
  6844.  
  6845. /*
  6846.  * types for inserting or deleting lines
  6847.  */
  6848. #define USE_T_CAL   1
  6849. #define USE_T_CDL   2
  6850. #define USE_T_AL    3
  6851. #define USE_T_CE    4
  6852. #define USE_T_DL    5
  6853. #define USE_T_SR    6
  6854. #define USE_NL        7
  6855. #define USE_T_CD    8
  6856. #define USE_REDRAW  9
  6857.  
  6858. /*
  6859.  * insert lines on the screen and update ScreenLines[]
  6860.  * 'end' is the line after the scrolled part. Normally it is Rows.
  6861.  * When scrolling region used 'off' is the offset from the top for the region.
  6862.  * 'row' and 'end' are relative to the start of the region.
  6863.  *
  6864.  * return FAIL for failure, OK for success.
  6865.  */
  6866.     static int
  6867. screen_ins_lines(off, row, line_count, end, wp)
  6868.     int        off;
  6869.     int        row;
  6870.     int        line_count;
  6871.     int        end;
  6872.     win_T    *wp;        /* NULL or window to use width from */
  6873. {
  6874.     int        i;
  6875.     int        j;
  6876.     unsigned    temp;
  6877.     int        cursor_row;
  6878.     int        type;
  6879.     int        result_empty;
  6880.     int        can_ce = can_clear(T_CE);
  6881.  
  6882.     /*
  6883.      * FAIL if
  6884.      * - there is no valid screen
  6885.      * - the screen has to be redrawn completely
  6886.      * - the line count is less than one
  6887.      * - the line count is more than 'ttyscroll'
  6888.      */
  6889.     if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
  6890.     return FAIL;
  6891.  
  6892.     /*
  6893.      * There are seven ways to insert lines:
  6894.      * 0. When in a vertically split window and t_CV isn't set, redraw the
  6895.      *    characters from ScreenLines[].
  6896.      * 1. Use T_CD (clear to end of display) if it exists and the result of
  6897.      *      the insert is just empty lines
  6898.      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
  6899.      *      present or line_count > 1. It looks better if we do all the inserts
  6900.      *      at once.
  6901.      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
  6902.      *      insert is just empty lines and T_CE is not present or line_count >
  6903.      *      1.
  6904.      * 4. Use T_AL (insert line) if it exists.
  6905.      * 5. Use T_CE (erase line) if it exists and the result of the insert is
  6906.      *      just empty lines.
  6907.      * 6. Use T_DL (delete line) if it exists and the result of the insert is
  6908.      *      just empty lines.
  6909.      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
  6910.      *      the 'da' flag is not set or we have clear line capability.
  6911.      * 8. redraw the characters from ScreenLines[].
  6912.      *
  6913.      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
  6914.      * the scrollbar for the window. It does have insert line, use that if it
  6915.      * exists.
  6916.      */
  6917.     result_empty = (row + line_count >= end);
  6918. #ifdef FEAT_VERTSPLIT
  6919.     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
  6920.     type = USE_REDRAW;
  6921.     else
  6922. #endif
  6923.     if (can_clear(T_CD) && result_empty)
  6924.     type = USE_T_CD;
  6925.     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
  6926.     type = USE_T_CAL;
  6927.     else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
  6928.     type = USE_T_CDL;
  6929.     else if (*T_AL != NUL)
  6930.     type = USE_T_AL;
  6931.     else if (can_ce && result_empty)
  6932.     type = USE_T_CE;
  6933.     else if (*T_DL != NUL && result_empty)
  6934.     type = USE_T_DL;
  6935.     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
  6936.     type = USE_T_SR;
  6937.     else
  6938.     return FAIL;
  6939.  
  6940.     /*
  6941.      * For clearing the lines screen_del_lines() is used. This will also take
  6942.      * care of t_db if necessary.
  6943.      */
  6944.     if (type == USE_T_CD || type == USE_T_CDL ||
  6945.                      type == USE_T_CE || type == USE_T_DL)
  6946.     return screen_del_lines(off, row, line_count, end, FALSE, wp);
  6947.  
  6948.     /*
  6949.      * If text is retained below the screen, first clear or delete as many
  6950.      * lines at the bottom of the window as are about to be inserted so that
  6951.      * the deleted lines won't later surface during a screen_del_lines.
  6952.      */
  6953.     if (*T_DB)
  6954.     screen_del_lines(off, end - line_count, line_count, end, FALSE, wp);
  6955.  
  6956. #ifdef FEAT_CLIPBOARD
  6957.     /* Remove a modeless selection when inserting lines halfway the screen
  6958.      * or not the full width of the screen. */
  6959.     if (off + row > 0
  6960. # ifdef FEAT_VERTSPLIT
  6961.         || (wp != NULL && wp->w_width != Columns)
  6962. # endif
  6963.        )
  6964.     clip_clear_selection();
  6965.     else
  6966.     clip_scroll_selection(-line_count);
  6967. #endif
  6968.  
  6969. #ifdef FEAT_GUI_BEOS
  6970.     vim_lock_screen();
  6971. #endif
  6972. #ifdef FEAT_GUI
  6973.     /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
  6974.      * scrolling is actually carried out. */
  6975.     gui_dont_update_cursor();
  6976. #endif
  6977.  
  6978.     if (*T_CCS != NUL)       /* cursor relative to region */
  6979.     cursor_row = row;
  6980.     else
  6981.     cursor_row = row + off;
  6982.  
  6983.     /*
  6984.      * Shift LineOffset[] line_count down to reflect the inserted lines.
  6985.      * Clear the inserted lines in ScreenLines[].
  6986.      */
  6987.     row += off;
  6988.     end += off;
  6989.     for (i = 0; i < line_count; ++i)
  6990.     {
  6991. #ifdef FEAT_VERTSPLIT
  6992.     if (wp != NULL && wp->w_width != Columns)
  6993.     {
  6994.         /* need to copy part of a line */
  6995.         j = end - 1 - i;
  6996.         while ((j -= line_count) >= row)
  6997.         linecopy(j + line_count, j, wp);
  6998.         j += line_count;
  6999.         if (can_clear((char_u *)" "))
  7000.         lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
  7001.         else
  7002.         lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
  7003.     }
  7004.     else
  7005. #endif
  7006.     {
  7007.         j = end - 1 - i;
  7008.         temp = LineOffset[j];
  7009.         while ((j -= line_count) >= row)
  7010.         LineOffset[j + line_count] = LineOffset[j];
  7011.         LineOffset[j + line_count] = temp;
  7012.         if (can_clear((char_u *)" "))
  7013.         lineclear(temp, (int)Columns);
  7014.         else
  7015.         lineinvalid(temp, (int)Columns);
  7016.     }
  7017.     }
  7018. #ifdef FEAT_GUI_BEOS
  7019.     vim_unlock_screen();
  7020. #endif
  7021.  
  7022.     screen_stop_highlight();
  7023.     windgoto(cursor_row, 0);
  7024.  
  7025. #ifdef FEAT_VERTSPLIT
  7026.     /* redraw the characters */
  7027.     if (type == USE_REDRAW)
  7028.     redraw_block(row, end, wp);
  7029.     else
  7030. #endif
  7031.     if (type == USE_T_CAL)
  7032.     {
  7033.     term_append_lines(line_count);
  7034.     screen_start();        /* don't know where cursor is now */
  7035.     }
  7036.     else
  7037.     {
  7038.     for (i = 0; i < line_count; i++)
  7039.     {
  7040.         if (type == USE_T_AL)
  7041.         {
  7042.         if (i && cursor_row != 0)
  7043.             windgoto(cursor_row, 0);
  7044.         out_str(T_AL);
  7045.         }
  7046.         else  /* type == USE_T_SR */
  7047.         out_str(T_SR);
  7048.         screen_start();        /* don't know where cursor is now */
  7049.     }
  7050.     }
  7051.  
  7052.     /*
  7053.      * With scroll-reverse and 'da' flag set we need to clear the lines that
  7054.      * have been scrolled down into the region.
  7055.      */
  7056.     if (type == USE_T_SR && *T_DA)
  7057.     {
  7058.     for (i = 0; i < line_count; ++i)
  7059.     {
  7060.         windgoto(off + i, 0);
  7061.         out_str(T_CE);
  7062.         screen_start();        /* don't know where cursor is now */
  7063.     }
  7064.     }
  7065.  
  7066. #ifdef FEAT_GUI
  7067.     gui_can_update_cursor();
  7068.     if (gui.in_use)
  7069.     out_flush();    /* always flush after a scroll */
  7070. #endif
  7071.     return OK;
  7072. }
  7073.  
  7074. /*
  7075.  * delete lines on the screen and update ScreenLines[]
  7076.  * 'end' is the line after the scrolled part. Normally it is Rows.
  7077.  * When scrolling region used 'off' is the offset from the top for the region.
  7078.  * 'row' and 'end' are relative to the start of the region.
  7079.  *
  7080.  * Return OK for success, FAIL if the lines are not deleted.
  7081.  */
  7082. /*ARGSUSED*/
  7083.     int
  7084. screen_del_lines(off, row, line_count, end, force, wp)
  7085.     int        off;
  7086.     int        row;
  7087.     int        line_count;
  7088.     int        end;
  7089.     int        force;        /* even when line_count > p_ttyscroll */
  7090.     win_T    *wp;        /* NULL or window to use width from */
  7091. {
  7092.     int        j;
  7093.     int        i;
  7094.     unsigned    temp;
  7095.     int        cursor_row;
  7096.     int        cursor_end;
  7097.     int        result_empty;    /* result is empty until end of region */
  7098.     int        can_delete;    /* deleting line codes can be used */
  7099.     int        type;
  7100.  
  7101.     /*
  7102.      * FAIL if
  7103.      * - there is no valid screen
  7104.      * - the screen has to be redrawn completely
  7105.      * - the line count is less than one
  7106.      * - the line count is more than 'ttyscroll'
  7107.      */
  7108.     if (!screen_valid(TRUE) || line_count <= 0 ||
  7109.                      (!force && line_count > p_ttyscroll))
  7110.     return FAIL;
  7111.  
  7112.     /*
  7113.      * Check if the rest of the current region will become empty.
  7114.      */
  7115.     result_empty = row + line_count >= end;
  7116.  
  7117.     /*
  7118.      * We can delete lines only when 'db' flag not set or when 'ce' option
  7119.      * available.
  7120.      */
  7121.     can_delete = (*T_DB == NUL || can_clear(T_CE));
  7122.  
  7123.     /*
  7124.      * There are six ways to delete lines:
  7125.      * 0. When in a vertically split window and t_CV isn't set, redraw the
  7126.      *    characters from ScreenLines[].
  7127.      * 1. Use T_CD if it exists and the result is empty.
  7128.      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
  7129.      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
  7130.      *      none of the other ways work.
  7131.      * 4. Use T_CE (erase line) if the result is empty.
  7132.      * 5. Use T_DL (delete line) if it exists.
  7133.      * 6. redraw the characters from ScreenLines[].
  7134.      */
  7135. #ifdef FEAT_VERTSPLIT
  7136.     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
  7137.     type = USE_REDRAW;
  7138.     else
  7139. #endif
  7140.     if (can_clear(T_CD) && result_empty)
  7141.     type = USE_T_CD;
  7142. #if defined(__BEOS__) && defined(BEOS_DR8)
  7143.     /*
  7144.      * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
  7145.      * its internal termcap... this works okay for tests which test *T_DB !=
  7146.      * NUL.  It has the disadvantage that the user cannot use any :set t_*
  7147.      * command to get T_DB (back) to empty_option, only :set term=... will do
  7148.      * the trick...
  7149.      * Anyway, this hack will hopefully go away with the next OS release.
  7150.      * (Olaf Seibert)
  7151.      */
  7152.     else if (row == 0 && T_DB == empty_option
  7153.                     && (line_count == 1 || *T_CDL == NUL))
  7154. #else
  7155.     else if (row == 0 && (
  7156. #ifndef AMIGA
  7157.     /* On the Amiga, somehow '\n' on the last line doesn't always scroll
  7158.      * up, so use delete-line command */
  7159.                 line_count == 1 ||
  7160. #endif
  7161.                         *T_CDL == NUL))
  7162. #endif
  7163.     type = USE_NL;
  7164.     else if (*T_CDL != NUL && line_count > 1 && can_delete)
  7165.     type = USE_T_CDL;
  7166.     else if (can_clear(T_CE) && result_empty
  7167. #ifdef FEAT_VERTSPLIT
  7168.         && (wp == NULL || wp->w_width == Columns)
  7169. #endif
  7170.         )
  7171.     type = USE_T_CE;
  7172.     else if (*T_DL != NUL && can_delete)
  7173.     type = USE_T_DL;
  7174.     else if (*T_CDL != NUL && can_delete)
  7175.     type = USE_T_CDL;
  7176.     else
  7177.     return FAIL;
  7178.  
  7179. #ifdef FEAT_CLIPBOARD
  7180.     /* Remove a modeless selection when deleting lines halfway the screen or
  7181.      * not the full width of the screen. */
  7182.     if (off + row > 0
  7183. # ifdef FEAT_VERTSPLIT
  7184.         || (wp != NULL && wp->w_width != Columns)
  7185. # endif
  7186.        )
  7187.     clip_clear_selection();
  7188.     else
  7189.     clip_scroll_selection(line_count);
  7190. #endif
  7191.  
  7192. #ifdef FEAT_GUI_BEOS
  7193.     vim_lock_screen();
  7194. #endif
  7195. #ifdef FEAT_GUI
  7196.     /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
  7197.      * scrolling is actually carried out. */
  7198.     gui_dont_update_cursor();
  7199. #endif
  7200.  
  7201.     if (*T_CCS != NUL)        /* cursor relative to region */
  7202.     {
  7203.     cursor_row = row;
  7204.     cursor_end = end;
  7205.     }
  7206.     else
  7207.     {
  7208.     cursor_row = row + off;
  7209.     cursor_end = end + off;
  7210.     }
  7211.  
  7212.     /*
  7213.      * Now shift LineOffset[] line_count up to reflect the deleted lines.
  7214.      * Clear the inserted lines in ScreenLines[].
  7215.      */
  7216.     row += off;
  7217.     end += off;
  7218.     for (i = 0; i < line_count; ++i)
  7219.     {
  7220. #ifdef FEAT_VERTSPLIT
  7221.     if (wp != NULL && wp->w_width != Columns)
  7222.     {
  7223.         /* need to copy part of a line */
  7224.         j = row + i;
  7225.         while ((j += line_count) <= end - 1)
  7226.         linecopy(j - line_count, j, wp);
  7227.         j -= line_count;
  7228.         if (can_clear((char_u *)" "))
  7229.         lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
  7230.         else
  7231.         lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
  7232.     }
  7233.     else
  7234. #endif
  7235.     {
  7236.         /* whole width, moving the line pointers is faster */
  7237.         j = row + i;
  7238.         temp = LineOffset[j];
  7239.         while ((j += line_count) <= end - 1)
  7240.         LineOffset[j - line_count] = LineOffset[j];
  7241.         LineOffset[j - line_count] = temp;
  7242.         if (can_clear((char_u *)" "))
  7243.         lineclear(temp, (int)Columns);
  7244.         else
  7245.         lineinvalid(temp, (int)Columns);
  7246.     }
  7247.     }
  7248. #ifdef FEAT_GUI_BEOS
  7249.     vim_unlock_screen();
  7250. #endif
  7251.  
  7252.     screen_stop_highlight();
  7253.  
  7254. #ifdef FEAT_VERTSPLIT
  7255.     /* redraw the characters */
  7256.     if (type == USE_REDRAW)
  7257.     redraw_block(row, end, wp);
  7258.     else
  7259. #endif
  7260.     if (type == USE_T_CD)    /* delete the lines */
  7261.     {
  7262.     windgoto(cursor_row, 0);
  7263.     out_str(T_CD);
  7264.     screen_start();            /* don't know where cursor is now */
  7265.     }
  7266.     else if (type == USE_T_CDL)
  7267.     {
  7268.     windgoto(cursor_row, 0);
  7269.     term_delete_lines(line_count);
  7270.     screen_start();            /* don't know where cursor is now */
  7271.     }
  7272.     /*
  7273.      * Deleting lines at top of the screen or scroll region: Just scroll
  7274.      * the whole screen (scroll region) up by outputting newlines on the
  7275.      * last line.
  7276.      */
  7277.     else if (type == USE_NL)
  7278.     {
  7279.     windgoto(cursor_end - 1, 0);
  7280.     for (i = line_count; --i >= 0; )
  7281.         out_char('\n');        /* cursor will remain on same line */
  7282.     }
  7283.     else
  7284.     {
  7285.     for (i = line_count; --i >= 0; )
  7286.     {
  7287.         if (type == USE_T_DL)
  7288.         {
  7289.         windgoto(cursor_row, 0);
  7290.         out_str(T_DL);        /* delete a line */
  7291.         }
  7292.         else /* type == USE_T_CE */
  7293.         {
  7294.         windgoto(cursor_row + i, 0);
  7295.         out_str(T_CE);        /* erase a line */
  7296.         }
  7297.         screen_start();        /* don't know where cursor is now */
  7298.     }
  7299.     }
  7300.  
  7301.     /*
  7302.      * If the 'db' flag is set, we need to clear the lines that have been
  7303.      * scrolled up at the bottom of the region.
  7304.      */
  7305.     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
  7306.     {
  7307.     for (i = line_count; i > 0; --i)
  7308.     {
  7309.         windgoto(cursor_end - i, 0);
  7310.         out_str(T_CE);        /* erase a line */
  7311.         screen_start();        /* don't know where cursor is now */
  7312.     }
  7313.     }
  7314.  
  7315. #ifdef FEAT_GUI
  7316.     gui_can_update_cursor();
  7317.     if (gui.in_use)
  7318.     out_flush();    /* always flush after a scroll */
  7319. #endif
  7320.  
  7321.     return OK;
  7322. }
  7323.  
  7324. /*
  7325.  * show the current mode and ruler
  7326.  *
  7327.  * If clear_cmdline is TRUE, clear the rest of the cmdline.
  7328.  * If clear_cmdline is FALSE there may be a message there that needs to be
  7329.  * cleared only if a mode is shown.
  7330.  * Return the length of the message (0 if no message).
  7331.  */
  7332.     int
  7333. showmode()
  7334. {
  7335.     int        need_clear;
  7336.     int        length = 0;
  7337.     int        do_mode;
  7338.     int        attr;
  7339.     int        nwr_save;
  7340. #ifdef FEAT_INS_EXPAND
  7341.     int        sub_attr;
  7342. #endif
  7343.  
  7344.     do_mode = (p_smd && ((State & INSERT) || restart_edit
  7345. #ifdef FEAT_VISUAL
  7346.         || VIsual_active
  7347. #endif
  7348.         ));
  7349.     if (do_mode || Recording)
  7350.     {
  7351.     /*
  7352.      * Don't show mode right now, when not redrawing or inside a mapping.
  7353.      * Call char_avail() only when we are going to show something, because
  7354.      * it takes a bit of time.
  7355.      */
  7356.     if (!redrawing() || (char_avail() && !KeyTyped))
  7357.     {
  7358.         redraw_cmdline = TRUE;        /* show mode later */
  7359.         return 0;
  7360.     }
  7361.  
  7362.     nwr_save = need_wait_return;
  7363.  
  7364.     /* wait a bit before overwriting an important message */
  7365.     check_for_delay(FALSE);
  7366.  
  7367.     /* if the cmdline is more than one line high, erase top lines */
  7368.     need_clear = clear_cmdline;
  7369.     if (clear_cmdline && cmdline_row < Rows - 1)
  7370.         msg_clr_cmdline();            /* will reset clear_cmdline */
  7371.  
  7372.     /* Position on the last line in the window, column 0 */
  7373.     msg_pos_mode();
  7374.     cursor_off();
  7375.     attr = hl_attr(HLF_CM);            /* Highlight mode */
  7376.     if (do_mode)
  7377.     {
  7378.         MSG_PUTS_ATTR("--", attr);
  7379. #if defined(FEAT_XIM)
  7380.         if (xic != NULL && im_get_status() && !p_imdisable
  7381.                     && curbuf->b_p_iminsert == B_IMODE_IM)
  7382.         MSG_PUTS_ATTR(" XIM", attr);
  7383. #endif
  7384. #if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
  7385.         if (gui.in_use)
  7386.         {
  7387.         if (hangul_input_state_get())
  7388.             MSG_PUTS_ATTR(" ÇѱÛ", attr);   /* HANGUL */
  7389.         }
  7390. #endif
  7391. #ifdef FEAT_INS_EXPAND
  7392.         if (edit_submode != NULL)        /* CTRL-X in Insert mode */
  7393.         {
  7394.         /* These messages can get long, avoid a wrap in a narrow
  7395.          * window.  Prefer showing edit_submode_extra. */
  7396.         length = (Rows - msg_row) * Columns - 3;
  7397.         if (edit_submode_extra != NULL)
  7398.             length -= vim_strsize(edit_submode_extra);
  7399.         if (length > 0)
  7400.         {
  7401.             if (edit_submode_pre != NULL)
  7402.             length -= vim_strsize(edit_submode_pre);
  7403.             if (length - vim_strsize(edit_submode) > 0)
  7404.             {
  7405.             if (edit_submode_pre != NULL)
  7406.                 msg_puts_attr(edit_submode_pre, attr);
  7407.             msg_puts_attr(edit_submode, attr);
  7408.             }
  7409.             if (edit_submode_extra != NULL)
  7410.             {
  7411.             MSG_PUTS_ATTR(" ", attr);  /* add a space in between */
  7412.             if ((int)edit_submode_highl < (int)HLF_COUNT)
  7413.                 sub_attr = hl_attr(edit_submode_highl);
  7414.             else
  7415.                 sub_attr = attr;
  7416.             msg_puts_attr(edit_submode_extra, sub_attr);
  7417.             }
  7418.         }
  7419.         length = 0;
  7420.         }
  7421.         else
  7422. #endif
  7423.         {
  7424. #ifdef FEAT_VREPLACE
  7425.         if (State & VREPLACE_FLAG)
  7426.             MSG_PUTS_ATTR(_(" VREPLACE"), attr);
  7427.         else
  7428. #endif
  7429.             if (State & REPLACE_FLAG)
  7430.             MSG_PUTS_ATTR(_(" REPLACE"), attr);
  7431.         else if (State & INSERT)
  7432.         {
  7433. #ifdef FEAT_RIGHTLEFT
  7434.             if (p_ri)
  7435.             MSG_PUTS_ATTR(_(" REVERSE"), attr);
  7436. #endif
  7437.             MSG_PUTS_ATTR(_(" INSERT"), attr);
  7438.         }
  7439.         else if (restart_edit == 'I')
  7440.             MSG_PUTS_ATTR(_(" (insert)"), attr);
  7441.         else if (restart_edit == 'R')
  7442.             MSG_PUTS_ATTR(_(" (replace)"), attr);
  7443.         else if (restart_edit == 'V')
  7444.             MSG_PUTS_ATTR(_(" (vreplace)"), attr);
  7445. #ifdef FEAT_RIGHTLEFT
  7446.         if (p_hkmap)
  7447.             MSG_PUTS_ATTR(_(" Hebrew"), attr);
  7448. # ifdef FEAT_FKMAP
  7449.         if (p_fkmap)
  7450.             MSG_PUTS_ATTR(farsi_text_5, attr);
  7451. # endif
  7452. #endif
  7453. #ifdef FEAT_KEYMAP
  7454.         if (State & LANGMAP)
  7455.             MSG_PUTS_ATTR(_(" (lang)"), attr);
  7456. #endif
  7457.         if ((State & INSERT) && p_paste)
  7458.             MSG_PUTS_ATTR(_(" (paste)"), attr);
  7459.  
  7460. #ifdef FEAT_VISUAL
  7461.         if (VIsual_active)
  7462.         {
  7463.             if (VIsual_select)
  7464.             MSG_PUTS_ATTR(_(" SELECT"), attr);
  7465.             else
  7466.             MSG_PUTS_ATTR(_(" VISUAL"), attr);
  7467.             if (VIsual_mode == Ctrl_V)
  7468.             MSG_PUTS_ATTR(_(" BLOCK"), attr);
  7469.             else if (VIsual_mode == 'V')
  7470.             MSG_PUTS_ATTR(_(" LINE"), attr);
  7471.         }
  7472. #endif
  7473.         MSG_PUTS_ATTR(" --", attr);
  7474.         }
  7475.         need_clear = TRUE;
  7476.     }
  7477.     if (Recording
  7478. #ifdef FEAT_INS_EXPAND
  7479.         && edit_submode == NULL        /* otherwise it gets too long */
  7480. #endif
  7481.         )
  7482.     {
  7483.         MSG_PUTS_ATTR(_("recording"), attr);
  7484.         need_clear = TRUE;
  7485.     }
  7486.     if (need_clear || clear_cmdline)
  7487.         msg_clr_eos();
  7488.     msg_didout = FALSE;        /* overwrite this message */
  7489.     length = msg_col;
  7490.     msg_col = 0;
  7491.     need_wait_return = nwr_save;    /* never ask for hit-return for this */
  7492.     }
  7493.     else if (clear_cmdline)        /* just clear anything */
  7494.     msg_clr_cmdline();        /* will reset clear_cmdline */
  7495.  
  7496. #ifdef FEAT_CMDL_INFO
  7497.     /* If the last window has no status line, the ruler is after the mode
  7498.      * message and must be redrawn */
  7499. # ifdef FEAT_WINDOWS
  7500.     if (lastwin->w_status_height == 0)
  7501. # endif
  7502.     win_redr_ruler(lastwin, TRUE);
  7503. #endif
  7504.     redraw_cmdline = FALSE;
  7505.     clear_cmdline = FALSE;
  7506.  
  7507.     return length;
  7508. }
  7509.  
  7510. /*
  7511.  * Position for a mode message.
  7512.  */
  7513.     static void
  7514. msg_pos_mode()
  7515. {
  7516.     msg_col = 0;
  7517.     msg_row = Rows - 1;
  7518. }
  7519.  
  7520. /*
  7521.  * Delete mode message.  Used when ESC is typed which is expected to end
  7522.  * Insert mode (but Insert mode didn't end yet!).
  7523.  */
  7524.     void
  7525. unshowmode(force)
  7526.     int        force;
  7527. {
  7528.     /*
  7529.      * Don't delete it right now, when not redrawing or insided a mapping.
  7530.      */
  7531.     if (!redrawing() || (!force && char_avail() && !KeyTyped))
  7532.     redraw_cmdline = TRUE;        /* delete mode later */
  7533.     else
  7534.     {
  7535.     msg_pos_mode();
  7536.     if (Recording)
  7537.         MSG_PUTS_ATTR(_("recording"), hl_attr(HLF_CM));
  7538.     msg_clr_eos();
  7539.     }
  7540. }
  7541.  
  7542. #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
  7543. /*
  7544.  * Get the character to use in a status line.  Get its attributes in "*attr".
  7545.  */
  7546.     static int
  7547. fillchar_status(attr, is_curwin)
  7548.     int        *attr;
  7549.     int        is_curwin;
  7550. {
  7551.     int fill;
  7552.     if (is_curwin)
  7553.     {
  7554.     *attr = hl_attr(HLF_S);
  7555.     fill = fill_stl;
  7556.     }
  7557.     else
  7558.     {
  7559.     *attr = hl_attr(HLF_SNC);
  7560.     fill = fill_stlnc;
  7561.     }
  7562.     /* Use fill when there is highlighting, and highlighting of current
  7563.      * window differs, or the fillchars differ, or this is not the
  7564.      * current window */
  7565.     if (*attr != 0 && ((hl_attr(HLF_S) != hl_attr(HLF_SNC)
  7566.             || !is_curwin || firstwin == lastwin)
  7567.             || (fill_stl != fill_stlnc)))
  7568.     return fill;
  7569.     if (is_curwin)
  7570.     return '^';
  7571.     return '=';
  7572. }
  7573. #endif
  7574.  
  7575. #ifdef FEAT_VERTSPLIT
  7576. /*
  7577.  * Get the character to use in a separator between vertically split windows.
  7578.  * Get its attributes in "*attr".
  7579.  */
  7580.     static int
  7581. fillchar_vsep(attr)
  7582.     int        *attr;
  7583. {
  7584.     *attr = hl_attr(HLF_C);
  7585.     if (*attr == 0 && fill_vert == ' ')
  7586.     return '|';
  7587.     else
  7588.     return fill_vert;
  7589. }
  7590. #endif
  7591.  
  7592. /*
  7593.  * Return TRUE if redrawing should currently be done.
  7594.  */
  7595.     int
  7596. redrawing()
  7597. {
  7598.     return (!RedrawingDisabled && !(p_lz && char_avail() && !KeyTyped));
  7599. }
  7600.  
  7601. /*
  7602.  * Return TRUE if printing messages should currently be done.
  7603.  */
  7604.     int
  7605. messaging()
  7606. {
  7607.     return (!(p_lz && char_avail() && !KeyTyped));
  7608. }
  7609.  
  7610. /*
  7611.  * Show current status info in ruler and various other places
  7612.  * If always is FALSE, only show ruler if position has changed.
  7613.  */
  7614.     void
  7615. showruler(always)
  7616.     int        always;
  7617. {
  7618.     if (!always && !redrawing())
  7619.     return;
  7620. #if defined(FEAT_STL_OPT) && defined(FEAT_WINDOWS)
  7621.     if (*p_stl && curwin->w_status_height)
  7622.     win_redr_custom(curwin, FALSE);
  7623.     else
  7624. #endif
  7625. #ifdef FEAT_CMDL_INFO
  7626.     win_redr_ruler(curwin, always);
  7627. #endif
  7628.  
  7629. #ifdef FEAT_TITLE
  7630.     if (need_maketitle
  7631. # ifdef FEAT_STL_OPT
  7632.         || (p_icon && (stl_syntax & STL_IN_ICON))
  7633.         || (p_title && (stl_syntax & STL_IN_TITLE))
  7634. # endif
  7635.        )
  7636.     maketitle();
  7637. #endif
  7638. }
  7639.  
  7640. #ifdef FEAT_CMDL_INFO
  7641.     static void
  7642. win_redr_ruler(wp, always)
  7643.     win_T    *wp;
  7644.     int        always;
  7645. {
  7646.     char_u    buffer[70];
  7647.     int        row;
  7648.     int        fillchar;
  7649.     int        attr;
  7650.     int        empty_line = FALSE;
  7651.     colnr_T    virtcol;
  7652.     int        i;
  7653.     int        o;
  7654. #ifdef FEAT_VERTSPLIT
  7655.     int        this_ru_col;
  7656.     int        off = 0;
  7657.     int        width = Columns;
  7658. # define WITH_OFF(x) x
  7659. # define WITH_WIDTH(x) x
  7660. #else
  7661. # define WITH_OFF(x) 0
  7662. # define WITH_WIDTH(x) Columns
  7663. # define this_ru_col ru_col
  7664. #endif
  7665.  
  7666.     /* If 'ruler' off or redrawing disabled, don't do anything */
  7667.     if (!p_ru)
  7668.     return;
  7669.  
  7670.     /*
  7671.      * Check if cursor.lnum is valid, since win_redr_ruler() may be called
  7672.      * after deleting lines, before cursor.lnum is corrected.
  7673.      */
  7674.     if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
  7675.     return;
  7676.  
  7677. #ifdef FEAT_INS_EXPAND
  7678.     /* Don't draw the ruler while doing insert-completion, it might overwrite
  7679.      * the (long) mode message. */
  7680. # ifdef FEAT_WINDOWS
  7681.     if (wp == lastwin && lastwin->w_status_height == 0)
  7682. # endif
  7683.     if (edit_submode != NULL)
  7684.         return;
  7685. #endif
  7686.  
  7687. #ifdef FEAT_STL_OPT
  7688.     if (*p_ruf)
  7689.     {
  7690.     win_redr_custom(wp, TRUE);
  7691.     return;
  7692.     }
  7693. #endif
  7694.  
  7695.     /*
  7696.      * Check if the line is empty (will show "0-1").
  7697.      */
  7698.     if (*ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
  7699.     empty_line = TRUE;
  7700.  
  7701.     /*
  7702.      * Only draw the ruler when something changed.
  7703.      */
  7704.     validate_virtcol_win(wp);
  7705.     if (       redraw_cmdline
  7706.         || always
  7707.         || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
  7708.         || wp->w_cursor.col != wp->w_ru_cursor.col
  7709.         || wp->w_virtcol != wp->w_ru_virtcol
  7710. #ifdef FEAT_VIRTUALEDIT
  7711.         || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
  7712. #endif
  7713.         || wp->w_topline != wp->w_ru_topline
  7714. #ifdef FEAT_DIFF
  7715.         || wp->w_topfill != wp->w_ru_topfill
  7716. #endif
  7717.         || empty_line != wp->w_ru_empty)
  7718.     {
  7719.     cursor_off();
  7720. #ifdef FEAT_WINDOWS
  7721.     if (wp->w_status_height)
  7722.     {
  7723.         row = W_WINROW(wp) + wp->w_height;
  7724.         fillchar = fillchar_status(&attr, wp == curwin);
  7725. # ifdef FEAT_VERTSPLIT
  7726.         off = W_WINCOL(wp);
  7727.         width = W_WIDTH(wp);
  7728. # endif
  7729.     }
  7730.     else
  7731. #endif
  7732.     {
  7733.         row = Rows - 1;
  7734.         fillchar = ' ';
  7735.         attr = 0;
  7736. #ifdef FEAT_VERTSPLIT
  7737.         width = Columns;
  7738.         off = 0;
  7739. #endif
  7740.     }
  7741.  
  7742.     /* In list mode virtcol needs to be recomputed */
  7743.     virtcol = wp->w_virtcol;
  7744.     if (wp->w_p_list && lcs_tab1 == NUL)
  7745.     {
  7746.         wp->w_p_list = FALSE;
  7747.         getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
  7748.         wp->w_p_list = TRUE;
  7749.     }
  7750.  
  7751.     /*
  7752.      * Some sprintfs return the length, some return a pointer.
  7753.      * To avoid portability problems we use strlen() here.
  7754.      */
  7755.     sprintf((char *)buffer, "%ld,",
  7756.         (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
  7757.             ? 0L
  7758.             : (long)(wp->w_cursor.lnum));
  7759.     col_print(buffer + STRLEN(buffer),
  7760.         !(State & INSERT) && empty_line
  7761.             ? 0
  7762.             : (int)wp->w_cursor.col + 1,
  7763.         (int)virtcol + 1);
  7764.  
  7765.     /*
  7766.      * Add a "50%" if there is room for it.
  7767.      * On the last line, don't print in the last column (scrolls the
  7768.      * screen up on some terminals).
  7769.      */
  7770.     i = (int)STRLEN(buffer);
  7771.     get_rel_pos(wp, buffer + i + 1);
  7772.     o = (int)STRLEN(buffer + i + 1);
  7773. #ifdef FEAT_WINDOWS
  7774.     if (wp->w_status_height == 0)    /* can't use last char of screen */
  7775. #endif
  7776.         ++o;
  7777. #ifdef FEAT_VERTSPLIT
  7778.     this_ru_col = ru_col - (Columns - width);
  7779.     if (this_ru_col < 0)
  7780.         this_ru_col = 0;
  7781. #endif
  7782.     /* Never use more than half the window/screen width, leave the other
  7783.      * half for the filename. */
  7784.     if (this_ru_col < (WITH_WIDTH(width) + 1) / 2)
  7785.         this_ru_col = (WITH_WIDTH(width) + 1) / 2;
  7786.     if (this_ru_col + i + o < WITH_WIDTH(width))
  7787.     {
  7788.         while (this_ru_col + i + o < WITH_WIDTH(width))
  7789.         buffer[i++] = fillchar;
  7790.         get_rel_pos(wp, buffer + i);
  7791.     }
  7792.     /* Truncate at window boundary. */
  7793.     if (this_ru_col + (int)STRLEN(buffer) > WITH_WIDTH(width))
  7794.         buffer[WITH_WIDTH(width) - this_ru_col] = NUL;
  7795.  
  7796.     screen_puts(buffer, row, this_ru_col + WITH_OFF(off), attr);
  7797.     i = redraw_cmdline;
  7798.     screen_fill(row, row + 1,
  7799.         this_ru_col + WITH_OFF(off) + (int)STRLEN(buffer),
  7800.         (int)(WITH_OFF(off) + WITH_WIDTH(width)),
  7801.         fillchar, fillchar, attr);
  7802.     /* don't redraw the cmdline because of showing the ruler */
  7803.     redraw_cmdline = i;
  7804.     wp->w_ru_cursor = wp->w_cursor;
  7805.     wp->w_ru_virtcol = wp->w_virtcol;
  7806.     wp->w_ru_empty = empty_line;
  7807.     wp->w_ru_topline = wp->w_topline;
  7808. #ifdef FEAT_DIFF
  7809.     wp->w_ru_topfill = wp->w_topfill;
  7810. #endif
  7811.     }
  7812. }
  7813. #endif
  7814.